Capturing Form component attributes into a data structure

Hello Friends:

Soon, I’ll be creating a simple, pretty flat Form (on purpose) with all components in the top-level container (I believe it’s a Column Panel).

All variations of that Form will have a RichText Box for data-entry as the first component (top), followed by either RadioButtons, or CheckBoxes, or a plain TextBox for additional user input and choices (below that RichText box I mentioned above).

When a User completes this Form, I want to capture various component attributes in a JSON document, which can be saved (perhaps in a Data Table).

I was thinking of using Pydantic to help with this (which I’ve never used before) or even manual JSON creation.

The idea is to use these JSON documents to populate similar Forms later on (in other words, to reverse the operation).

I can do it, but am wondering if anyone had done this already and might offer tips, ideas, examples from their case.

I’ll read them and it will help me with ideas as well as be more efficient.

Just examples of JSON created saved, then read back in.

Thank you!

You don’t need to use json.

In anvil, you could store those attributes in a python dict on the client side. If you send that dict to a server function (for saving in a data table, perhaps), anvil will handle the json serialisation and deserialisation for you and you just work with a python dict on the server side. The same happens in reverse if you retrieve the values and send them to the client as a dict.

To misquote Terry Pratchett, it’s pythons all the way down!

If you want to venture further, you could even use a portable class instead of a simple dict.

2 Likes

Hi! All good points overall. Thank you.

Indeed, I actually did mean a nested dict() too, which in Python I sometimes use interchangeably with JSON (even if slightly inaccurate).

I haven’t started this yet (it’s 5:40am here lol), but I’m imagining starting with self. of the top-level Form, traversing it, picking out the components and attributes that I want (ignoring the rest), and sending it to, indeed, a Data Table. Or perhaps just saving the entire dict() representation of self., and then selecting the components and attributes I desire at read-back time.

Given that the Form’s self. is an instantiated Class, I’d need to think about how to pickle it to its dict() representation; or perhaps just try to save the Python pickle() of self. itself, and storing that to a Data Table.

Is that the approach you meant, more or less?

Hi @nmvega,

Popping in to add: This is a perfect use case for Data Bindings! You can use data bindings to automatically populate the dict as the user edits the components, and then to automatically populate the components when you reload the data from storage.

2 Likes

OMG, I think you just saved my life. :laughing:

Please let me explain a bit further to ask how your suggestion might be applied here, because I haven’t yet made it to the Data Bindings section yet (though it’s been calling my name).

Okay, during my prototyping (and learning Anvil Works) phase, I created three Forms, each of which renders a Question in a non-editable RichText box; and depending on the Form, permits an Answer below the Question via either a:

  1. TextInput box

  2. RadioButtons in a Group

  3. CheckBoxes

Each Form version has a slightly different Submit/Continue button navigation workflow (which I’ve taken care of).

(SideNote: More precisely, these are SubForms that programmatically get added to the main, top-level Form. Just adding that detail. :slight_smile:).

But now that prototyping is complete, I need to turn this on it’s head. Ideally, I would like to now “adjust” those same three Forms (without create new ones), such that someone else (content creators) (a) can type in the RichText content Question, and then (b) also provide the corresponding correct Answer:

  1. For the TextInput Answer Form version, that answers is specified via a TextInput Box.

  2. For the RadioButtons Answer Form version, they need to specify the correct Selection, and each button’s visible text and the value.

  3. And for the CheckBoxes Answer Form version, they need to specify the correct Choice(s) and the visible text for each Choice.

They don’t have to specify the workflow logic or event handlers for buttons or navigation links that happen to be on those Forms (I prefer they be invisible to them, actually). I already coded that. These are just content producer people who need to populate a Question box, and one of three Answers formats. And when they signal that they are done (say, by clicking an “I’m Done” button), ideally I want to pickle that populated Form and save it to a Data Table.

Then, when those same populated Forms are rendered to persons taking a survey, they see the RichText Question box but it’s non-editable , and a place to specify their answer (one of three formats). But they can’t see the embedded answers.

In other words, these are the same pickled Forms, but render slightly differently to the content producer versus to the survey taker.

How can Data Binding help me here? I will read up on them now. Thank you.

What do you mean by pickled Forms?

Good question.

I’m not yet sure if it’s possible, but since instantiated Forms (e.g. MyForm(…)) are instantiated Python, I was imagining using Python’s marshal, json or pickle Module (or something else) to serialize it to a Simple Object column.

First, though, I need to architect how to apply the same Form differently for content creators versus survey takers in an elegant way (… besides adding additional components and hiding / unhiding them depending on the role the Form is being used in: ie, content creator versus survey taker).

Ideally it would be:

  1. Content creator adds content to a Form (with additional components visible to a content creator but invisible to the survey taker). Maybe Data Bindings can eliminate the need for said additional components.
  2. Pickle the completed Form to a Data Table as is.
  3. Retrieve that Form from the Data Table, Unpickle it and, render it with components specific to survey taking view visible (and components specific to creator creation view invisible). And again, maybe Data Bindings can eliminate the need for said additional components.

95%, and preferably 100%, of the components would be the same for each “view”. Because I really want a WYSIWYG approach, and maybe Data Bindings can help this goal.

I hope that helps. :slight_smile:

PS: Picking the entire SubForm might be a bit much to ask (and may fail because it’s a larger and more complex data-structure), but if Data Bindings can capture Form component attribute values, then perhaps I can serialize those via Data Bindings capture. I’ll begin to read on Data Bindings shortly. I have to get my AM coffee first. LoL Thank you all in advance!

I don’t fully understand the big picture of what you are trying to do, but whether you create the form in the IDE or dynamically from code, serializing/deserialising it could give you half working objects, maybe with the correct html, but I’m afraid Anvil will not be able to work with it. Events, databinding and other magics may not not work (I haven’t tried, just a feeling).

If the forms are designed with the IDE, then all you need to do is pick the right form and play with databinding. You will store something like {'form': 'FormAbc', 'value1': 123, 'value2': 'xyz'}.

If the forms are generated dynamically, then you can add details about what components are to be placed in the form.
Something like:

[
    {'type': 'checkbox', 'text': 'Click me!', 'checked': True},
    {'type': 'radiobutton', 'text': 'No, click me!', 'selected': True},
]

Then you can add the required components at run time. This way Anvil creates the components first, then renders them to html. After creating each component you can also add event listeners and do whatever you like.

You can see an example of dynamic creation of components based on a list of dictionaries on the InputBox: Input_box() and alert2()


EDIT
Maybe you can use the input_box itself to show different input forms. I am using it in all my apps now :slight_smile: (obviously only if (1) it covers your use cases and (2) it looks good enough for your app)

2 Likes

I’ve done this in a different context, and I’ll echo the other advice, serialized forms are not what you want. In the simplest case, have all the answer components be present on the form, and make one of them visible based on the data given by the content creator. For more complex cases, as @stefano.menci says, create the components/sub forms dynamically.

1 Like

Good morning again @stefano.menci @jshaffstall

Okay, I won’t serialize the Forms (I didn’t like the whole form idea anyway, as I alluded). However, I will be serializing component attributes populated by content creators, which are the simplest of data types (True, False, int, str, etc) and shouldn’t pose a problem.

The SubForm’s components, look & feel, UI/UX, will never change even one bit (that’s not the content creators role). They are complete as I have designed them.

So, I’ll just do:

  • For content creator: Instantiate SubForm1(…); unhide only components material to the content creator; let them complete it; and finally capture the relevant attributes of the now-populated SubForm1() instance (not the whole Form) into a Data Table.

Then, do the reverse (unwind this) for the servey taker:

  • For Survey Taker: Read in attributes dict() from the Data Table; Instantiate a SubForm1(…) (initially all or most components are hidden); populate that instance’s content-related attributes from said dict(); and finally, unhide only those components material to the servey taker; and off the servey taker runs.

I’ll know how which “render path” to take (content creator versus survey taker) based on eMail login (the User table has an is_SurveyTaker boolean column).

Again, there are no dynamic Forms (I’ve designed them and they won’t change). Only component attributes values change and whether or not to make them visible.

So I think I see how to approach this (as I just described).

I just need to read up on Data Bindings (which I’m doing now). That seems useful as described by @meredydd and described by @stefano.menci

Thank you for the guidance! :hugs:

1 Like

Hello. Is there a something like a RichText Box, but that accepts user input of Markdown content and renders it as such while being input? (Similar to a Jupyter Notebook Markdown Cellthough this doesn’t involve Jupyter - just using that as an example).

Perhaps this will help?

1 Like

Thank you. Looks interesting. I’ll forego this particular solution right now (I’m already down too many rabbit holes at the moment). For now I’ll stick to stock components. :slight_smile:

What I do in similar situations is provide the input box where they type their marked up content, and a preview box, where they see what it will look like. I found that far easier than trying to get a WYSIWYG editor working the way I wanted.

1 Like

:laughing: This is exactly what I was doing right now: Two boxes vertically stacked in the same card. The top box is a plain TextArea with placeholder instruction to type or paste in their Markdown content (… I also included a URL to a free online Markdown editor - StackEdit); and then immediately below that is the RichText box for grabbing the above content and inserting it there for previewing. Is that basically what you did, too? (Confirming). Thank you.

PS: It requires a bit more event handling (to copy over the text), hiding and unhiding, etc, but at least I understant it.

That’s basically what I did, yes. My upper editing area was a Code Mirror instance with toolbar buttons to make it easier for the content creators (I was having them use bbcode, and the toolbar buttons automatically insert the matching tags), but the concept’s the same.

1 Like

I’m wondering if I should try the RichText box’s change event, or its lost-focus event, or provide a click-to-preview button (last resort because it’s another component to manage). I haven’t yet tried the change event anywhere, so I don’t know if it fires just for an initial character input of a RichText box, or for every character as they type (which would be cool, but could be a performance drag; or maybe not). The latter (fires for each character change) makes more sense.

I was supposed to be working on Data Bindings and Form attribute capturing (i.e. subject of this question) when I ran into not having a Markdown TextArea component available. I’ll get back to that after solving this Markdown preview situation.

EDIT: I’ll just use a separate card component for this markdown composing need with a TextArea, RichText and Button (to click to update the preview). Then I’ll just hide / unhide the entire card. That’s easier.

I used the change event on the editor, and didn’t see any performance impact. It’s all client side, and the content involved wasn’t much more than a page or two of marked up text. The live preview was super convenient.

2 Likes

I have the same setup: a TextArea for the user to edit, its change event updates the content of a RichText and does some validation checks and hides or shows and updates a Label when the text does not follow the correct guidelines.

2 Likes

@jshaffstall @stefano.menci The change event works beautifully and with no lag. Thank you for inputs.

1 Like