Hey,
I built a page that saves text that someone writes in two existing text boxes to a data table. I have a button (Add additional line) that produces a third text box, if the first two do not suffice. The text from this third box is not saved and I get the error: object has no attribute ‘new_text_box’
I guess the issue is that this text box does not exist before the button (Add additional line) is pushed.
Here my client code:
def button_1_click(self, **event_args):
"""This method is called when the button is clicked"""
# Create a new TextBox and add placeholder text
new_text_box = TextBox()
new_text_box.placeholder = "Enter project output"
# Add TextBox just above button_1, that is in linear_panel_1
self.linear_panel_1.add_component(new_text_box)
def button_2_click(self, **event_args):
"""This method is called when the button is clicked"""
#Calls the server code to add text to data table, only saves text if not empty
anvil.server.call('add_to_table', self.text_box_1.text) if self.text_box_1.text!='' else None
anvil.server.call('add_to_table', self.text_box_2.text) if self.text_box_2.text!='' else None
#Does not exist before button is clicked and thus does not work. How to solve this?
anvil.server.call('add_to_table', self.new_text_box.text)
# Navigate to Page 2
open_form('Page2')```
Here’s my server code:
@anvil.server.callable
def add_to_table(output):
#adds the output given to the table in the column 'output'
app_tables.responses.add_row(output=output)
Thanks a lot for any hints!
Best,
Julian
That’s because new_text_box is a local variable in the function you add it, not an attribute of the form. If you add self. to the beginning of the variable name when you define it and add it, then it will work.
Thanks Duncan, this works nicely!
Yet, when I add more than one new text box, only the input from the last one is saved, while the input from the other ones does not make it into the data table.
Also, if I do not add an additional text box I get an error saying: object has no attribute ‘new_text_box’
Again my code now looks as follows:
def button_1_click(self, **event_args):
"""This method is called when the button is clicked"""
# Create a new TextBox and give the self. prefix to make it exist also outside of this function so it can be called in button_2_click
self.new_text_box = TextBox()
# add placeholder text
self.new_text_box.placeholder = "Enter project output"
# Add TextBox just above button_1, that is in linear_panel_1
self.linear_panel_1.add_component(self.new_text_box)
def button_2_click(self, **event_args):
"""This method is called when the button is clicked"""
#Calls the server code to add text to data table, only saves text if not empty
anvil.server.call('add_to_table', self.text_box_1.text) if self.text_box_1.text!='' else None
anvil.server.call('add_to_table', self.text_box_2.text) if self.text_box_2.text!='' else None
#Issue: if more than one new text box is added only the text from the last one is saved...
anvil.server.call('add_to_table', self.new_text_box.text) if self.new_text_box.text!='' else None
# Navigate to Page 2
open_form('Page2')
You could use get_components()
:
def button_1_click(self, **event_args):
# Create a new TextBox and add placeholder text
new_text_box = TextBox()
new_text_box.placeholder = "Enter project output"
# Add TextBox just above button_1, that is in linear_panel_1
self.linear_panel_1.add_component(new_text_box)
def button_2_click(self, **event_args):
#Calls the server code to add text to data table, only saves text if not empty
for text_box in self.linear_panel_1.get_components():
if text_box.text:
anvil.server.call('add_to_table', text_box.text)
open_form('Page2')
But it would be faster if you did only one server call:
# on the client
def button_2_click(self, **event_args):
#Calls the server code to add text to data table, only saves text if not empty
texts = []
for text_box in self.linear_panel_1.get_components():
if text_box.text:
texts.append(text_box.text)
anvil.server.call('add_to_table', texts)
open_form('Page2')
# on the server
@anvil.server.callable
def add_to_table(texts):
#adds the output given to the table in the column 'output'
for text in texts:
app_tables.responses.add_row(output=text)
Which in my opinion it would be cleaner with a list comprehension:
# on the client
def button_2_click(self, **event_args):
#Calls the server code to add text to data table, only saves text if not empty
texts = [text_box.text
for text_box in self.linear_panel_1.get_components()
if text_box.text]
anvil.server.call('add_to_table', texts)
open_form('Page2')
2 Likes
The first approach worked perfectly for me, thanks a lot! 