Skip to content

Latest commit

 

History

History
383 lines (308 loc) · 14.3 KB

27a_edit_assessment_code.md

File metadata and controls

383 lines (308 loc) · 14.3 KB

Edit Assessments Code

- Implementing event handlers for edit and save buttons.
- Transferring assessment details to edit fields and toggling element visibility.
- Writing updates to a backend Assessments table.
- Updating display elements after saving.
- Testing the functionality to ensure correct behavior.

Planning

The code is going to react to two events:

  • button_edit click
  • button_save click

So, lets go ahead and create those two event handlers.

Open the AssessmentPanel in Design mode:

  1. click on each button
  2. select on click event

event handlers

Code

Button edit click

When the user clicks the edit button, we want to web app to:

  • take the values of the assessment item from this specific panel and write them into the edit elements
  • make all the display element invisible
  • make all the edit elements visible

Open the AssessmentPanel in Code mode.

In the button_edit_click handler use the code below to copy the values from the display elements.

:linenos:
:lineno-start: 27
:emphasize-lines: 2-5
  def button_edit_click(self, **event_args):
    self.text_box_subject.text = self.item["subject"]
    self.text_box_details.text = self.item["details"]
    self.date_picker_start.date = self.item["start_date"]
    self.date_picker_due.date = self.item["due_date"]
:class: notice
- **line 28** → takes **subject** value for specific assessment for this panel and saves it as the text for the subject text box.
- **line 29** → takes **details** value for specific assessment for this panel and saves it as the text for the details text box.
- **line 30** → takes **start_date** value for specific assessment for this panel and saves it as the date for the start date picker
- **line 31** → takes **due_date** value for specific assessment for this panel and saves it as the date for the due date picker

Now we need to change the visibility of the elements. To do this we will create a separate function that swaps the visibility of each element, ie. if visibility was True it will make it False.

We will do this with one function that will work for both event handlers. Add the highlighted code below to the bottom of the AssessmentPanel code.

:linenos:
:lineno-start: 33
:emphasize-lines: 5-18
  def button_save_click(self, **event_args):
    """This method is called when the button is clicked"""
    pass
    
  def switch_components(self):
    # display elements
    self.label_subject.visible = not self.label_subject.visible
    self.label_details.visible = not self.label_details.visible
    self.label_start.visible = not self.label_start.visible
    self.label_due.visible = not self.label_due.visible
    self.button_edit.visible = not self.button_edit.visible
    
    # edit elements
    self.text_box_subject.visible = not self.text_box_subject.visible
    self.text_box_details.visible = not self.text_box_details.visible
    self.date_picker_start.visible = not self.date_picker_start.visible
    self.date_picker_due.visible = not self.date_picker_due.visible
    self.button_save.visible = not self.button_save.visible
:class: notice
- **line 37** → create the **switch_components** method
- **lines 39 - 43** → swaps the **visibility** value for each of the display elements
- **lines 46 - 50** → swaps the **visibility** value for each of the edit elements

Finally, to call the switch_components method from the button_edit_click handler, add the highlighted code.

:linenos:
:lineno-start: 27
:emphasize-lines: 6
  def button_edit_click(self, **event_args):
    self.text_box_subject.text = self.item["subject"]
    self.text_box_details.text = self.item["details"]
    self.date_picker_start.date = self.item["start_date"]
    self.date_picker_due.date = self.item["due_date"]
    self.switch_components()
:class: notice
- **line 32** → called the **switch_component** method

Test the edit button

Launch your website and test if the edit button works. You may need to adjust the width of your columns to make everything fit.

edit button test

If you have fixed you column widths, then it is time to make the save button work.

Button save click

When the user clicks the Save button we want the following to happen:

  • take the values of all the edit elements and write them the Assessments table
  • take the values from the edit elements and write them to the display elements
  • make all the edit elements invisible
  • make all the display elements visible

assessment_update

To achieve the first step, we will need to call a backend function to save the values to the Assessments table. So open the assessments_service, and add the highlighted code to the end.

:linenos:
:lineno-start: 26
:emphasize-lines: 7 - 15
@anvil.server.callable
def update_assessment_completed(assessment_id, completed):
  assessment = app_tables.assessments.get_by_id(assessment_id)
  if assessment:
    assessment["completed"] = completed

@anvil.server.callable
def update_assessment(assessment_id, subject, details, start_date, due_date, completed):
    assessment = app_tables.assessments.get_by_id(assessment_id)
    if assessment:
        assessment['subject'] = subject
        assessment['details'] = details
        assessment['start_date'] = start_date
        assessment['due_date'] = due_date
        assessment['completed'] = completed
:class: notice
- **line 26** → makes this function callable by the frontend
- **line 27** → create the `update_assessments` function which requires the following data to be passed:
  - assessment_id
  - subject
  - details
  - start_date
  - due_date
  - completed
- **line 34** → loads the assessment that has the passed `assessment_id`
- **line 35** → checks to see if there is an assessment with the passed `assessment_id`
- **lines 36 - 40** → overwrites the stored values of the assessment with the values passed

Now that we have our backend function to call, we can work on the button_save_click handler.

button_save_click

Open the AssessmentPanel in code mode.

First thing we will do is write the values to the Assessments table. Go to the button_save_click handler and replace lines 35 and 36 with the highlighted code below:

:linenos:
:lineno-start: 34
:emphasize-lines: 2 - 9
  def button_save_click(self, **event_args):
    # write to server
    anvil.server.call('update_assessment', 
                     self.item.get_id(),
                     self.text_box_subject.text,
                     self.text_box_details.text,
                     self.date_picker_start.date,
                     self.date_picker_due.date,
                     self.check_box_completed.checked)
:class: notice
- **line 35** → a comment to help structure the method
- **lines 36 - 42** → calls the function we just created in the **assessment_service**. The first argument needs to be the name of the function being called. The other arguments are the date the function needs passed.
- **line 37** → gets the id of the assessment for this specific panel.

Next we need to take all the values from the edit elements and write them to the display elements, so the display reflects the changes made.

Add the highlighted code to the end of the button_save_click event handler.

:linenos:
:lineno-start: 34
:emphasize-lines: 11 - 15
  def button_save_click(self, **event_args):
    # write to server
    anvil.server.call('update_assessment', 
                     self.item.get_id(),
                     self.text_box_subject.text,
                     self.text_box_details.text,
                     self.date_picker_start.date,
                     self.date_picker_due.date,
                     self.check_box_completed.checked)

    # update display
    self.label_subject.text = self.text_box_subject.text
    self.label_details.text = self.text_box_details.text
    self.label_start.text = self.date_picker_start.date.strftime('%d/%m/%Y')
    self.label_due.text = self.date_picker_due.date.strftime('%d/%m/%Y')
:class: notice
- **line 44** → a comment to help structure the method
- **line 45** → assigns the value in the subject text box to the subject label
- **line 46** → assigns the value in the details text box to the details label
- **line 47** → assigns the date in the start date picker to the start label
- **line 48** → assigns the date in the due date picker to the due label

Finally, we need to turn all the edit elements invisible and all the display elements visible. Luckily we created a method that swaps all those elements visibility values, so we can just call that.

:linenos:
:lineno-start: 34
:emphasize-lines: 16
  def button_save_click(self, **event_args):
    # write to server
    anvil.server.call('update_assessment', 
                     self.item.get_id(),
                     self.text_box_subject.text,
                     self.text_box_details.text,
                     self.date_picker_start.date,
                     self.date_picker_due.date,
                     self.check_box_completed.checked)

    # update display
    self.label_subject.text = self.text_box_subject.text
    self.label_details.text = self.text_box_details.text
    self.label_start.text = self.date_picker_start.date.strftime('%d/%m/%Y')
    self.label_due.text = self.date_picker_due.date.strftime('%d/%m/%Y')
    self.switch_components()
  • line 49 → call the switch component method to reverse the visibility of the edit and display elements.

Testing

You should be able to change the values of your assessments. Launch your webapp, and try to change the details. Make sure that you test all values (subject, details, start date and due date).

Final code state

By the end of this tutorial your code should be the same as below:

AssessmentPanel

:linenos:
from ._anvil_designer import AssessmentPanelTemplate
from anvil import *
import anvil.server
import anvil.users
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import datetime


class AssessmentPanel(AssessmentPanelTemplate):
  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.
    self.check_box_completed.checked = self.item['completed']
    self.label_subject.text = self.item['subject']
    self.label_details.text = self.item['details']
    self.label_start.text = self.item['start_date'].strftime('%d/%m/%Y')
    self.label_due.text = self.item['due_date'].strftime('%d/%m/%Y')

  def check_box_completed_change(self, **event_args):
    new_value = self.check_box_completed.checked
    anvil.server.call('update_assessment_completed', self.item.get_id(),new_value)

  def button_edit_click(self, **event_args):
    self.text_box_subject.text = self.item["subject"]
    self.text_box_details.text = self.item["details"]
    self.date_picker_start.date = self.item["start_date"]
    self.date_picker_due.date = self.item["due_date"]
    self.switch_components()

  def button_save_click(self, **event_args):
    # write to server
    anvil.server.call('update_assessment', 
                     self.item.get_id(),
                     self.text_box_subject.text,
                     self.text_box_details.text,
                     self.date_picker_start.date,
                     self.date_picker_due.date,
                     self.check_box_completed.checked)

    # update display
    self.label_subject.text = self.text_box_subject.text
    self.label_details.text = self.text_box_details.text
    self.label_start.text = self.date_picker_start.date.strftime('%d/%m/%Y')
    self.label_due.text = self.date_picker_due.date.strftime('%d/%m/%Y')
    self.switch_components()
  
  def switch_components(self):
    # display elements
    self.label_subject.visible = not self.label_subject.visible
    self.label_details.visible = not self.label_details.visible
    self.label_start.visible = not self.label_start.visible
    self.label_due.visible = not self.label_due.visible
    self.button_edit.visible = not self.button_edit.visible
    
    # edit elements
    self.text_box_subject.visible = not self.text_box_subject.visible
    self.text_box_details.visible = not self.text_box_details.visible
    self.date_picker_start.visible = not self.date_picker_start.visible
    self.date_picker_due.visible = not self.date_picker_due.visible
    self.button_save.visible = not self.button_save.visible

assessment_service

:linenos:
import anvil.users
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import anvil.server

@anvil.server.callable
def add_assessment(subject, details, start_date, due_date):
  user = anvil.users.get_user()
  
  app_tables.assessments.add_row(user= user,
                                 subject= subject,
                                 details=details,
                                 start_date=start_date,
                                 due_date=due_date,
                                 completed=False)

@anvil.server.callable
def get_assessment():
  user = anvil.users.get_user()

  return app_tables.assessments.search(tables.order_by('due_date'),
                                      user=user,
                                      completed=False)

@anvil.server.callable
def update_assessment_completed(assessment_id, completed):
  assessment = app_tables.assessments.get_by_id(assessment_id)
  if assessment:
    assessment["completed"] = completed

@anvil.server.callable
def update_assessment(assessment_id, subject, details, start_date, due_date, completed):
    assessment = app_tables.assessments.get_by_id(assessment_id)
    if assessment:
        assessment['subject'] = subject
        assessment['details'] = details
        assessment['start_date'] = start_date
        assessment['due_date'] = due_date
        assessment['completed'] = completed