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.
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.
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.