Anvil Community Forum

Capturing Form component attributes into a data structure

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

Hello!

I finally reached the point where I could use Data Binds, but still have questions after reading up a bit.

For a Form and each Component within it, how do each of their self.item[’ …’] relate to one another. Consider, for example, the tag attribute, which is available for a Form and virtually all Components within it …

If, say, for MyForm as well as for a Card component, a Drop-Down component, and a Nav-Link component within said MyForm, I Data-Bind their tag to self.item[‘foo’] – that is, to the identical dict() key string for each – how are each distinguished from one another? Does each have it’s own self.item[’…’]?

Understanding this will help me understand the data-structure and scope of self.item[…] (or for each self.item[…] if there are multiple in my contrived example) – crucially, so that I don’t clobber data. :sob:

Thank you in advance! :blush:

1 Like

The power of databinding is especially evident with repeating panels.

The very basic idea is:

  • You assign a list of items to a repeating panel: self.rp.items = [...]
  • Anvil uses the template form associated to the repeating panel self.rp to add a form instance per each item of self.rp.items, and assign that item to that form instance’s item.
  • The form instance has its own self.item automatically updated with its own item, whatever that item is

Typically the original list contains dictionary or dictionary like objects, like datatable rows or like any class that you may define as described in the “What to do” paragraph here.

Anvil helps you by pre-populating the expression in the databinding input box with self.item[] and tries to understand what makes sense inside the square brackets. For example, if it knows the type of the item contained in the list assigned to the repeating panel, it will auto complete with whatever keys are available for that dictionary. For example, if the list contains rows of a specific table, the autocompletion will suggest the column names.

Anvil suggests you should enter self.item[something], but that’s a python expression and you can put whatever you like. The only constraint is you shouldn’t use globals from other modules. Something like Globals.parameter_1 will not work. You will need to add self.parameter_1 = Globals.parameter_1 at the beginning of the the form.__init__, then use self.parameter_1 in the databinding.

I sometimes don’t even use self.item. For example, I am working now on a form that has def __init__(self, truck, **properties):, then I use self.truck.number, etc. in the databinding expressions, or self.truck in the databinding of the visible property of some components, so they are only visible if self.truck is defined.


I personally don’t like databinding because it’s just hidden python code, and I don’t like hidden python code. Creating a loop in the __init__ that takes care of assigning the values where they belong would do the same and would be more readable and searchable.

Said that, I use databinding all the times, because it’s so handy and easy to use.

I usd to never use databinding because errors in the code in the databinding expression used to be a nightmare to debug. They would just fail with very little feedback about the reason.

Then the errors started to show up as clickable links on the console (see here), so I started to use databinding.

Then that link stopped working (see here), but the information about the error is still there and it’s very helpful, so I still use databinding. A lot!

2 Likes