- Redirect users to a different screen after data is saved.
- Implement code reuse by copying and adapting existing code.
- Debug common runtime and logical errors in a web app.
- Use Anvil commands like `anvil.get_open_form()` for form references.
- Properly import components to ensure code functionality.
In last tutorial's test you would notice that once you have saved the details, the SetDetailsComponent remained loaded. What we want to do is load the AccountComponent so the user can see the current value of their first name and last name.
Admittedly, at the moment, the AccountComponent only has a title, but we'll fix that in the next tutorial.
The idea is pretty simple, we will need to add the step of loading the AccountComponent and change the lable_title_text to the end of the button_save_click handler. We can copy the appropriate code from link_account_click handler in the MainForm.
First we will copy the text we need.
- Open the MainForm in code mode and find the link_account_click handler.
- Copy the highlighted code
:linenos:
:lineno-start: 63
:emphasize-lines: 3 - 6
def link_account_click(self, **event_args):
"""This method is called when the link is clicked"""
self.content_panel.clear()
self.content_panel.add_component(AccountComponent())
self.label_title.text = self.breadcrumb_stem + " - Account"
self.set_active_link(("account"))
Now we need to paste it into the button_save_click handler.
- Open SetDetailsComponent in code mode and find the button_save_click handler
- Paste the code to the bottom of the handler, as below
:linenos:
:lineno-start: 17
:emphasize-lines: 18 - 21
def button_save_click(self, **event_args):
if self.text_box_first_name.text == "":
self.label_error.text = "First name cannot be blank"
self.label_error.visible = True
return
if self.text_box_last_name.text == "":
self.label_error.text = "Last name cannot be blank"
self.label_error.visible = True
return
self.label_error.visible = False
anvil.server.call("update_user",
self.text_box_first_name.text,
self.text_box_last_name.text)
self.content_panel.clear()
self.content_panel.add_component(AccountComponent())
self.label_title.text = self.breadcrumb_stem + " - Account"
self.set_active_link(("account"))
Now launch your website for testing:
- Register another user (you might have to logout first).
- Enter their first name and last name
- Click Save Details
- WHAT JUST HAPPENED?
You would have just got the following runtime error:
:class: note
Programming errors fall into three categories
1. **Syntax Errors**
- Occur when the code doesn't follow the rules of the programming language.
- Detected by the compiler or interpreter before running the code.
- Example: Missing a closing parenthesis.
2. **Runtime Errors**
- Occur during the execution of the program.
- Cause the program to crash or produce unexpected results.
- Example: Dividing by zero.
3. **Logic Errors**
- Occur when the code runs but produces incorrect results.
- Due to flaws in the logic of the code.
- Example: Incorrect formula in a calculation.
Well if says the error occurred at line 34 so lets start there:
self.content_panel.clear()
→ clear content_panel in self (this component).
You can see that the self is the problem. It refers to the component the code resides in (in this case the SetDetailsComponent), when we actually want to refer to MainForm where content_panel resides.
So we need a way to refer to the MainForm from with in the SetDetailsComponent code. Luckily Anvil provide a command to do this → anvil.get_open_form()
The Anvil command anvil.get_open_form()
returns the current open form, in our case it will be MainForm. This means we can get the MainForm, store it in a variable (main_form
). This will enable fixing the code we just pasted by replacing self
with main_form
.
Make the changes highlighted below.
:linenos:
:lineno-start: 17
:emphasize-lines: 18 - 22
def button_save_click(self, **event_args):
if self.text_box_first_name.text == "":
self.label_error.text = "First name cannot be blank"
self.label_error.visible = True
return
if self.text_box_last_name.text == "":
self.label_error.text = "Last name cannot be blank"
self.label_error.visible = True
return
self.label_error.visible = False
anvil.server.call("update_user",
self.text_box_first_name.text,
self.text_box_last_name.text)
main_form = get_open_form()
main_form.content_panel.clear()
main_form.content_panel.add_component(AccountComponent())
main_form.label_title.text = main_form.breadcrumb_stem + " - Account"
main_form.set_active_link(("account"))
Lets test again. The erroneous code came after writing the details to the User table, so you will need to delete those details to test again. then launch your website.
Now launch your website for testing:
- Register another user
- Enter their first name and last name
- Click Save Details
- WHAT AGAIN???
We still have an error. But look at the error closely, it's a different, so that's progress.
This error points to line 36.
main_form.content_panel.add_component(AccountComponent())
→ in the content_panel of the MainForm load the AccountComponent
It's complaining because there is no AccountComponent in the SetDetailsComponent. We resolved this issue in the MainForm by importing the AccountComponent using the following line:
from ..AccountComponent import AccountComponent
So we need to add this to the import statement at the top of SetDetailsComponent.
Open the SetDetailsComponent in code mode an then add the highlighted code below:
:linenos:
:lineno-start: 1
:emphasize-lines: 8
from ._anvil_designer import SetDetailsComponentTemplate
from anvil import *
import anvil.server
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import anvil.users
from ..AccountComponent import AccountComponent
Again, delete the user you just added and launch your website.
- Register another user
- Enter their first name and last name
- Click Save Details
- You should now be on the AccountComponent, stop your website and check that the user details have been saved to the User table
Now that is all working, we have to add details to the AccountComponent.
By the end of this tutorial your code should be the same as below:
:linenos:
from ._anvil_designer import SetDetailsComponentTemplate
from anvil import *
import anvil.server
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import anvil.users
from ..AccountComponent import AccountComponent
class SetDetailsComponent(SetDetailsComponentTemplate):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run before the form opens.
def button_save_click(self, **event_args):
if self.text_box_first_name.text == "":
self.label_error.text = "First name cannot be blank"
self.label_error.visible = True
return
if self.text_box_last_name.text == "":
self.label_error.text = "Last name cannot be blank"
self.label_error.visible = True
return
self.label_error.visible = False
anvil.server.call("update_user",
self.text_box_first_name.text,
self.text_box_last_name.text)
main_form = get_open_form()
main_form.content_panel.clear()
main_form.content_panel.add_component(AccountComponent())
main_form.label_title.text = main_form.breadcrumb_stem + " - Account"
main_form.set_active_link(("account"))