Looking for a better way to code this

I load an external dictionary of information via an API & I would like to modify existing fields dynamically. However I find myself repeating code. In the below example you’ll notice the code repeating 3 times.

For every instance, it checks if a relevant field is disabled, and if so, makes it invisible.
If it is Required, it changes the background color. Or else it assures that it is visible & that the background color is white.

The problem is that this quickly gets overwhelming. As I add new traits it becomes impossible to manage. Is there a way to access all of the components by passing a dictionary? Or even if I have to reference each field individually could I do the work in dictionary form & just pass the finalized dictionary rather than addressing each trait of that component inline?

for row in self.CONFIG['report_data']['report_list']:
  if row['Name'] == new_report:
    new_report_data = row
    break
if new_report_data.get('days_older_than','Disabled') != 'Disabled':
  self.text_days_older_than.visible = True
  if new_report_data.get('days_older_than','Required') == 'Required':
    self.text_days_older_than.background = "#d0f1fe"
  else:
    self.text_days_older_than.background = "white"
else: 
  self.text_days_older_than.visible = False      
  
if new_report_data.get('template_id','Disabled') != 'Disabled':
  self.drop_down_template_id.visible = True
  if new_report_data.get('template_id','Required') == 'Required':
    self.drop_down_template_id.background = "#d0f1fe"
  else:
    self.text_days_older_than.background = "white"
else: 
  self.drop_down_template_id.visible = False
  
if new_report_data.get('min_qty','Disabled') != 'Disabled':
  self.text_min_qty.visible = True
  if new_report_data.get('min_qty','Required') == 'Required':
    self.text_min_qty.background = "#d0f1fe"
  else:
    self.text_days_older_than.background = "white"
else: 
  self.text_min_qty.visible = False

What if you abstracted the if blocks into a function and passed the target components and necessary details as input arguments?

I do get your point. The code that I’ve displayed isn’t great. Given your suggestion it would look like this. And I agree that it would be less ugly. But it still leaves me writing one function for each trait (visible/background/etc) and manually mapping it to each field.

If it is not possible to do it otherwise in Anvil, then that’s the approach I will take. but I don’t want to misinterpret your response. Are you saying that it is not possible to update fields with a single dictionary?

for row in self.CONFIG['report_data']['report_list']:
  if row['Name'] == new_report:
    new_report_data = row
    break
  self.text_days_older_than.visible = someFunctionForVisible()
  self.text_days_older_than.background = someFunctionForBackground()
  self.drop_down_template_id.visible = someFunctionForVisible()
  self.drop_down_template_id.background = someFunctionForBackground()
  self.text_min_qty.visible = someFunctionForVisible()
  self.text_min_qty.background = someFunctionForBackground()

I was actually thinking that you would pass the components themselves into the function. You can test for their type or pass in another variable that indicates the information you need so that you can deal with them accordingly.

You could even put them all into a list (or dict) and pass that structure to the general function (and loop through the structure as needed).

Oh, and yes, you can update properties with a dictionary (although that alone wouldn’t solve the duplication issue completley from what I can tell). Like so:

my_text_box=TextBox(**{'foreground': 'black', 'background': 'red'})

Oh, and yes, you can update properties with a dictionary (although that alone wouldn’t solve the duplication issue completley from what I can tell). Like so:

my_text_box=TextBox(**{'foreground': 'black', 'background': 'red'})

I also thought that this would work, however I get an error message stating the following. It is apparently trying to create new fields rather than update existing ones.

AttributeError: Cannot set attribute ‘text_box’ on ‘Report’ form. There is already a component with this name.

For my purposes, creating entirely new fields dynamically would be even better than enabling hidden fields. However, I am not clear on how to do this. It seems they are being created somewhere, but nowhere that I can see.

I’m a python novice but would be tempted to try some combination of a eval() with a ternary expression for each new_report_data.get(‘key’,'value) (if I understand correctly). Then maybe it can be table driven so each field can have an expression to evaluate as a set of update/formatting rules.

Just a wild thought :slightly_smiling_face:

Hi @dev01, here is the link to create component dymatically:

You can add a component by creating an instance of the component class (e.g. calling  `Button()` ), and then calling  `add_component()`  on a container to add it to your page. For example:
self.button_1 = Button(text="Click me")
self.content_panel.add_component(self.button_1)

We all start somewhere. Good luck!

Thanks. I think this is the best case scenario for what I’m looking to do.

1 Like

Good luck @dev01 , I struggle to find that information in the first place as well.
If you have further issue, please feel free to reply or post another topic

1 Like