Chapter 4:
Allow users to edit movie data

We’ll now add the ability for the user to edit the information for individual movies.

Step 1: Add an edit button to the Data Grid

To allow the user to edit the information for a specific movie, we need a way for them to click on an individual movie. We’re going to add a Button to the RepeatingPanel’s RowTemplate. The RowTemplate is the Form that the RepeatingPanel uses to display each row of the list. First, add a column to the Data Grid by selecting the Data Grid itself and clicking the in the Object Palette. We don’t need a title for the column, and the data key doesn’t matter.

Location of the add column button in the Object Palette of the Data Grid

Double click on the RepeatingPanel to edit the RowTemplate. Drag a FlowPanel into the new column we just added and drag a Button into that FlowPanel. Name the Button edit_row, delete it’s text and set its icon to pencil. Add a click event handler to the Button using the Object Palette. We’ll write the click event function in Step 3.

Screen recording of adding a FlowPanel to the RowTemplate, adding a Button inside the FlowPanel and clicking 'on click event' in the Object Palette

Step 2: Write server code

We now need to write a function to edit the movie information. Since the movies Data Table cannot be written to by the client, we’ll write this function on the server.

To edit the movie data, we’ll write a server function that takes in a row from the movies table and updates its data if the data passes validation (in this case, if none of the fields are empty). Add the following code to ServerModule1:

@anvil.server.callable
def update_movie(movie, movie_data):
  if movie_data['director'] and movie_data['movie_name'] and movie_data['summary'] and movie_data['year']:
    movie.update(**movie_data)

Step 3: Edit the movie in a modal

When the user clicks the edit_row button, we want to present them with the MovieEdit Form in a modal so they can make changes to the movie. If the user clicks ‘OK’, we’ll then call the update_movie function we just wrote.

When building a CRUD app, it’s a good idea to keep all the CRUD related functions on your main Form, so we’ll present the modal and call the update_movie server function from the MovieList Form.

Switch back to the code for MovieList and add the following function:

def edit_movie(self, movie, **event_args):
  #movie is the row from the Data Table
  item = dict(movie)
  editing_form = MovieEdit(item=item)

  #if the user clicks OK on the alert
  if alert(content=editing_form, large=True):
    #pass in the Data Table row and the updated info
    anvil.server.call('update_movie', movie, item)
    #refresh the Data Grid
    self.repeating_panel_1.items = app_tables.movies.search()

We cannot directly pass the row from the movies Data Table into the MovieEdit Form because the Data Table cannot be modified from the client. So we convert it into a dictionary that can be modified, and then pass the movie row and the dictionary to the update_movie server function.

Step 4: Create the event handler

We now have a function in MovieList that lets the user edit a movie from the DataGrid, but we need to actually call that function. We want to call the function when the user clicks the edit_row Button, but that Button lives in the RepeatingPanel, not in MovieList.

The way we handle this is by setting a custom event handler on the RepeatingPanel. When that custom event is fired, we’ll call the edit_movie function. Note that custom events like this must start with x- to distinguish them from component events.

In MovieList, set a custom event handler on the RepeatingPanel called x-edit-movie and pass in the edit_movie function:

def __init__(self, **properties):
  # Set Form properties and Data Bindings.
  self.init_components(**properties)

  self.repeating_panel_1.items = app_tables.movies.search()
  #add this line to set the event handler
  self.repeating_panel_1.add_event_handler('x-edit-movie', self.edit_movie)

Go back to editing the code for the RepeatingPanel’s RowTemplate. Modify the edit_row Button’s click function so that it raises the RepeatingPanel’s x-edit-movie event. We’ll do that using self.parent since the RepeatingPanel is the RowTemplate’s parent Form:

def edit_row_click(self, **event_args):
  self.parent.raise_event('x-edit-movie', movie=self.item)

The edit_movie function requires one argument, movie, so when we raise the x-edit-movie event, we need to pass in self.item (the current row’s movie information).

Run the app and you should now be able to edit movie information.

Great! Users can now edit movies that are in the database. Next, we’ll add the ability to delete movies.

Chapter complete

Congratulations, you've completed this chapter!