Add Component Code¶
Now that we have create the layout for the AddComponent, we need to write the code to run it. Eventually we want to save the details to a table, but we haven’t made a table yet, so we will simply display the data as a save message
Planning¶
There are two events that will trigger code:
loading the component → initialise variable to store the user input
clicking the Add Assessment button → validate the user’s input, display save message and reset the form.
Coding¶
Now we know what we are doing, open the AddComponent in Code mode.
Initialising variable¶
We need to create variables to store all the user’s input. This needs to occur in the __init__
method.
10class AddComponent(AddComponentTemplate):
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14 self.subject = ""
15 self.details = ""
16 self.start = None
17 self.due = None
Code explaination
lines 14 & 15 → since Subject and Details store text, we create empty strings for their variables.
lines 16 & 15 → Start and Due are both dates, which are objects, so their empty variables are set using
None
We also need to make sure the error message is invisible.
10class AddComponent(AddComponentTemplate):
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14 self.subject = ""
15 self.details = ""
16 self.start = None
17 self.due = None
18
19 # Any code you write here will run before the form opens.
20 self.label_error.visible = False
Code explaination
line 20 → sets the label error to not vissible
Validation¶
Now we need to make the button_add_click
event handler.
The first code we add to the button_add_click
event handler checks that the user has entered data.
22 def button_add_click(self, **event_args):
23 # validation
24 if not self.text_box_subject.text:
25 self.label_error.visible = True
26 self.label_error.text = "Subject name needed"
27 elif not self.text_box_details.text:
28 self.label_error.visible = True
29 self.label_error.text = "Assessment details needed"
30 elif not self.date_picker_start.date:
31 self.label_error.visible = True
32 self.label_error.text = "Start date needed"
33 elif not self.date_picker_due.date:
34 self.label_error.visible = True
35 self.label_error.text = "Due date needed"
Code explaination
lines 24 & 27 → checks that the text box has a value (remember string truthiness)
lines 30 & 33 → checks that a date has been picked (remember object truthiness)
lines 25, 28, 31 & 34 → make the error message visible
lines 26, 29, 32 & 35 → display the error message
Validation testing¶
Launch your website and check that it produces an error message for each input element.
Save Message¶
Now we want to display a message to the user about what values will be saved.
22 def button_add_click(self, **event_args):
23 # validation
24 if not self.text_box_subject.text:
25 self.label_error.visible = True
26 self.label_error.text = "Subject name needed"
27 elif not self.text_box_details.text:
28 self.label_error.visible = True
29 self.label_error.text = "Assessment details needed"
30 elif not self.date_picker_start.date:
31 self.label_error.visible = True
32 self.label_error.text = "Start date needed"
33 elif not self.date_picker_due.date:
34 self.label_error.visible = True
35 self.label_error.text = "Due date needed"
36 else:
37 self.label_error.visible = True
38 self.subject = self.text_box_subject.text
39 self.details = self.text_box_details.text
40 self.start = self.date_picker_start.date
41 self.due = self.date_picker_due.date
42 self.label_error.text = f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded"
Code explaination
line 37 → makes the message available
lines 38 - 41 → reads the values from the form and stores them in the variables
line 42 → creates a string displaying the message and displays it in the error message label.
Save testing¶
Launch your website and check if it works. Enter a subject, assessment details, start date and due date, then click the Add Assessment button.
We can make a few observations from this test:
The save message should look the same as the error message
When the same message is presented, the input values in the form should be reset
Let’s fix those up.
Fixing messaging¶
The problem we have with the save message is that it is using the same format at the error message. There are two solutions:
Add another label for the save message, or
Change the format of the error label.
Neither one has an advantage over the other, so, for no particular reason, we will change the format of the error label.
This will involve changing the following label properties:
foreground colour
icon
bold
If we look at our code, this will need to happen for each of the error messages, as well as the save message. That means in five different locations. This is started to get quite repetitive. If we put this code through, and then decide to change the error foreground colour, we will need to fix it in multiple places. This is a classic example of the DRY principle. The means, it’s time to refactor.
Refactor plan¶
What we will do is create two methods to:
display an error message
display a save message
These methods will contain the appropriate formatting and then change the label text.
Speaking of the label, the name label_error doesn’t seem appropriate now, sow we will change it to label_message.
So, before refactoring the code, first change back to the Design mode and change the name of label_error to label_message.
Display error¶
Now, back in the Code mode, we will first create the display_error method
Under the button_add_click handler add the following code (be careful with your indentations).
44 def display_error(self, message):
45 self.label_message.visible = True
46 self.label_message.foreground = "#ff0000"
47 self.label_message.icon = "fa:exclamation-triangle"
48 self.label_message.bold = True
49 self.label_message.text = message
Code explaination
line 44 → creates the
display_error
method, which accepts an argument calledmessage
line 45 → turns the label visible
line 46 → changes the font colour to red
line 47 → sets the label’s icon
line 48 → makes the label bold
line 49 → makes the label display the message passed to it as an argument
Now go back to the button_add_click handler and replace all the error label code with a call to display_error.
22 def button_add_click(self, **event_args):
23 # validation
24 if not self.text_box_subject.text:
25 self.display_error("Subject name needed")
26 elif not self.text_box_details.text:
27 self.display_error("Assessment details needed")
28 elif not self.date_picker_start.date:
29 self.display_error("Start date needed")
30 elif not self.date_picker_due.date:
31 self.display_error("Due date needed")
32 else:
33 self.label_error.visible = True
34 self.subject = self.text_box_subject.text
35 self.details = self.text_box_details.text
36 self.start = self.date_picker_start.date
37 self.due = self.date_picker_due.date
38 self.label_error.text = f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded"
Display save¶
Now to add the display_save method.
Add the following code under the display_error method (remember to check indentation).
47 def display_save(self, message):
48 self.label_message.visible = True
49 self.label_message.foreground = "#000000"
50 self.label_message.icon = "fa:save"
51 self.label_message.bold = False
52 self.label_message.text = message
Code explaination
line 47 → creates the
display_save
method, which accepts an argument calledmessage
line 48 → turns the label visible
line 49 → changes the font colour to black
line 50 → sets the label’s icon
line 51 → makes the label not bold
line 52 → makes the label display the message passed to it as an argument
Now go back to the button_add_click handler and replace the save message code with a call to display_save.
32 else:
33 self.subject = self.text_box_subject.text
34 self.details = self.text_box_details.text
35 self.start = self.date_picker_start.date
36 self.due = self.date_picker_due.date
37 self.display_save(f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded")
Remove any other reference to label_error¶
Use Anvil’s search function to check if there are any more references to label_error in AddComponent and then fix them.
Test messaging¶
Launch your website and check that all the error messages and the save message work as planned.
Clear Form¶
The final step is to clear the user input and ready the form for the next assessment.
Under the display_save method add the following code:
54 def reset_form(self):
55 self.subject = ""
56 self.details = ""
57 self.start = None
58 self.due = None
59 self.text_box_subject.text = ""
60 self.text_box_details.text = ""
61 self.date_picker_start.date = None
62 self.date_picker_due.date = None
Code explaination
line 54 → creates the
reset_form
methodlines 55 - 58 → returns all the variables to their initialisation state
lines 59 - 62 → clears all the input from the elements
Since we only want to clear the form after it’s been saved, call the function from within the else section of the button_add_click handler.
32 else:
33 self.subject = self.text_box_subject.text
34 self.details = self.text_box_details.text
35 self.start = self.date_picker_start.date
36 self.due = self.date_picker_due.date
37 self.display_save(f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded")
38 self.reset_form()
Test clear form¶
Launch your website one more time and correctly enter all the required data. When you click the Add Assessment button, the save message should appear and all the input should be cleared.
Final code state¶
By the end of this tutorial your code should be the same as below:
Final AddComponent¶
1from ._anvil_designer import AddComponentTemplate
2from anvil import *
3import anvil.server
4import anvil.tables as tables
5import anvil.tables.query as q
6from anvil.tables import app_tables
7import anvil.users
8
9
10class AddComponent(AddComponentTemplate):
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14 self.subject = ""
15 self.details = ""
16 self.start = None
17 self.due = None
18
19 # Any code you write here will run before the form opens.
20 self.label_message.visible = False
21
22 def button_add_click(self, **event_args):
23 # validation
24 if not self.text_box_subject.text:
25 self.display_error("Subject name needed")
26 elif not self.text_box_details.text:
27 self.display_error("Assessment details needed")
28 elif not self.date_picker_start.date:
29 self.display_error("Start date needed")
30 elif not self.date_picker_due.date:
31 self.display_error("Due date needed")
32 else:
33 self.subject = self.text_box_subject.text
34 self.details = self.text_box_details.text
35 self.start = self.date_picker_start.date
36 self.due = self.date_picker_due.date
37 self.display_save(f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded")
38 self.reset_form()
39
40 def display_error(self, message):
41 self.label_message.visible = True
42 self.label_message.foreground = "#ff0000"
43 self.label_message.icon = "fa:exclamation-triangle"
44 self.label_message.bold = True
45 self.label_message.text = message
46
47 def display_save(self, message):
48 self.label_message.visible = True
49 self.label_message.foreground = "#000000"
50 self.label_message.icon = "fa:save"
51 self.label_message.bold = False
52 self.label_message.text = message
53
54 def reset_form(self):
55 self.subject = ""
56 self.details = ""
57 self.start = None
58 self.due = None
59 self.text_box_subject.text = ""
60 self.text_box_details.text = ""
61 self.date_picker_start.date = None
62 self.date_picker_due.date = None