Assign label text en masse

Hi all, I’ve got something like the following:

Each column is an instantiation of the same custom component and when I’m done with the form, there will be maybe 20 or so labels for each of those 6 columns you see. I’m pulling data from a remote database and bringing it all into Anvil via JSON.

Rather than assign each label individually, is there a way I can assign the text value to all the labels in one shot, like perhaps with a JSON or dict? If possible, I’d like to avoid having something like 120 lines of code to set those labels.

Or maybe there is a better way of structuring this? I thought about using a grid in each column instead of labels, but then each grid will be 1 column by 20 records or so, and I’d like to be able to apply special formatting (bold, underline, color, etc.) to any label.

Thanks,
David

Hi @david1,

depending on your specific use case, you could place all components in a conatainer (proboably they already are)

Then iterate over each element in the container and get the elements from some data source. (list + enumerate ist just to deomonstrate)

values = ['col1text','col2text'...]

for idx,component in enumerate(self.some_panel.get_components()):
    component.label1.text = values[idx]

Alternatively you could populate the panel right from code. This is what I personally do in most cases, since its much more flexible this way.

values = ['col1text','col2text'...]

for value in values:
    new_col = CustomCompoent(value)
    self.colum_panel_1.add_component(now_col)

Or you could use DataBinding instead (I don’t really use it but there is a bunch of stuff in the docs/forum on that)

Greetings,
Mark

1 Like

Aha. Mark, thanks for those ideas. I’m relatively new to Anvil so still working through the learning curve.

Seems like that second suggestion will end up with less code, and I could prep everything on the backend.

David

A little improvement to @mark.breuss example (forgive me if this is obvious, I don’t know your beginnerness level) would be to use dictionaries in the values list:

values = [
    {'col1': 'abc', 'col2': 'def'},
    {'col1': '123', 'col2': '456'},
]

So when you create a new instance with CustomCompoent(value) you pass all the values for its fields.

Then you can do self.item = values in the __init__ and get all populated with data binding.

Another alternative is to use a repeating panel instead of using a container and adding components one by one.

The repeating panel is a container that automatically adds forms to itself and populates each form when you do self.items = list_of_dictionaries_with_values. This one liner takes care of adding forms to the container, assigning a dictionary to the item member of the form and triggering its data binding.

A repeating panel will list your forms vertically rather than side by side. You could play with CSS to get them to show side by side (but that would be more difficult and time expensive and less readable and maintainable than following Mark’s suggestion and creating your own loop).

1 Like

Horizontally-repeating panels have been done here on the forum.

1 Like

Hi Stefano, yeah, much the newbie here. So if the custom component is named PinColumn2 and looks like the following (it is a card with a bunch of labels):

image

And I have the following dict (obviously hard-coded here for testing):

values = [
{‘label_pin’: ‘20-24-322-002-0001’, ‘label_agla’: ‘2,338’, ‘label_distance’: ‘0.000001’}
]

How would I get the labels in the custom component to display the values in my dict? For my app, there will always be 6 columns and I just dropped 6 instances of the custom component into the parent form. They are named custom_1 through custom_6 and I would know all label values.

Thanks,
David

EDIT: Not sure if this is right or not, but here’s what I ended up doing:

On the custom component, I manually set the data bindings, as shown below:

Then from the main component, I just ran the following:

values = [
  {'label_pin': '20-24-322-002-0001', 'label_agla': '2,338', 'label_distance': '0.000001'}
]

self.custom_1.item = values

And this is what came out:

Obviously, I need to fill in the rest, but I was also able to modify specific attributes of the label, like the color.