Introduction to Data Bindings
Published: 2024-05-23 18:51:29

Data Bindings are a useful feature in Anvil that make it easy to keep your UI components in sync with your data. A Data Binding associates a property of a component with a single Python expression, saving you from repeating similar sorts of assignments all over your code. In this tutorial we're going to look at what Data Bindings are, how you can use them, and common gotchas.

We're going to look at data bindings by developing an example app for logging our favorite movie. Our tutorial will have three main parts:

1. We'll build an app and use data bindings to display movie data
2. Next, we'll extend the functionality to edit the data
3. Then, we'll store the data to a Data Table
4. Finally, we'll make some changes so that edits to our data persist when the app is re-run

The final app will look something like this:

![Final App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6wc9urncpyb0n73bliq.png)

All of this is done in Anvil's hosted environment through your web browser, all in Python. 

If you're in a hurry, you can click [here](https://anvil.works/build#clone:T7JHC3NVHTP2UBWX%3dD3UJZJZBEWPJELCQQKPF3TZ4) to clone the app and explore the finished version in Anvil.

> If you're completely new to Anvil, you may want to try a [5-minute tutorial](https://anvil.works/learn/tutorials/feedback-form?utm_source=dev_to_data_binding) before beginning this tutorial.

Let's get started!

## What is a Data Binding?

When you want to display the contents of a variable in a visual component you would normally use code like this:

```
self.label_1.text = self.title
```

If you wanted to update the Label component when `self.title` changed, you would need to repeat that line of code in each place the variable changed. A data binding allows you to establish the relationship between the visual component and the variable once, eliminating all the assignment statements from your code.

## Chapter 1: Displaying Our Favorite Movie in a Form

We'll create an app that shows information about your favorite movie. We'll use data bindings to display data from a dictionary into Anvil components.

**Step 1: Create an App**

[Log in](https://anvil.works/login) to Anvil and click 'Create a new app'. Choose the Material Design 3 theme.

![Create the App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s4pu8xyu3l85ifte5dp.png)

That gives us an app with a [Form ](https://anvil.works/docs/ui#forms)named `Form1`.

**Step 2: Add components to your form**

We'll build our UI by dragging-and-dropping [components ](https://anvil.works/docs/ui/components)from the [Toolbox ](https://anvil.works/docs/editor#toolbox)into the page.

We want to display the movie name, the year it was released, the name of the director, and a summary of the movie's plot.

Add eight Labels, four for the titles of what we're displaying and four for the values to display. We'll also add a Label into the title slot.

![Creating the form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/huip51psi280hjxd8v1z.gif)

The final form should look something like this:

![The Final Form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lzvx5nnpx97b3faspj6.png)

**Step 3: Initialize data sources**

Every Anvil component and Form has an `item` property, meant specifically for storing data of any kind. Our data source will be a dictionary that we'll store in the `item` property of our Form.

Let's go to the Editor's [Code view](https://anvil.works/docs/editor#form-editor) and create this dictionary in the `__init__` function of the form:

```
class Form1(Form1Template):
    def __init__(self, **properties):
        self.item = {
            'movie_name': 'Back to the Future',
            'year': 1985,
            'director': 'Robert Zemeckis',
            'summary': 'Doc Brown invents a nuclear powered time machine, which Marty McFly '
                       'then uses to nearly erase himself from existence.'
        }
        
        # Set Form properties and Data Bindings.
        self.init_components(**properties)
```

Note that the dictionary is created before the call to `self.init_components`. This is because the data bindings are processed in that call, so our data source (the `self.item` dictionary) must be set up before that.

**Step 4: Set up data bindings**

Now we need to tell Anvil what data to associate with which components (e.g. the _data bindings_). We'll bind the data from our `self.item` dictionary to the `text` property of the Labels we just added.

To set up a data binding, click on the component that you want to have Anvil automatically set. I'll start with the label that will hold the name of the movie.

![Setup Data Binding](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fic600jnhgxki0ef5u8j.png)

You can find the `text` property at the top of the Properties Panel. We could type something in there but that would then always show that text. Instead, click the link icon to the right of the `text` property. This will cause the display to change and the link icon to turn blue, indicating that the data binding is active.

![Text Property](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhg648tf6y3mg8fmp574.png)

Set this data binding to the `movie_name` key of our dictionary:

![Data Binding](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r69d507q2qo5mkf1akpt.png)

We'll now do the same for the other labels, using `self.item['year']` for the year the movie was released, `self.item['director']` for the director's name, and `self.item['summary']` for the plot summary.

After those are set up, we can double check that the data bindings are correct by looking at the Form's Data Binding summary. You can find this by selecting your Form and scrolling to the bottom of the Properties Panel.

![Checking Data Bindings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pu923bwp3ohoek8nkoma.gif)

**Step 5: Run the app**

Your data bindings are all set! We've told the components which variables to pull data from to populate their text properties.

Run the app now and see the information about your movie displayed in the Form. We didn't need to use any code to set the `text` properties of any of the Labels, they were all set through the data bindings we set up in the Labels' `text` properties.

![Running the App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxmyj9fxwj211zxu3mvq.gif)


## Chapter 2: Edit Movie Data

We'll next allow the user to edit the movie data. For this, we'll use a feature of data bindings called [writeback](https://anvil.works/learn/tutorials/data-bindings/docs/client/data-bindings#two-way-data-bindings). You can toggle data binding writeback for user-editable components. This means that when a user changes a property that has a data binding, the original variable will be updated with the new value.

**Step 1: Create your edit form**

Create a second Form in your app by clicking the three dots to the right of Client Code and choose Add Form. Select Blank Panel and rename it to `MovieEdit`.

![Adding MovieEdit Form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4whktdia561015k7vrp.gif)

Start by dropping a ColumnPanel into the page. Setting up the Form is very similar to what we did with our previous Form, but we'll use TextBoxes instead of Labels, since we want the user to be able to edit the fields. Use a TextArea for the plot summary since that will usually be longer than a single line. This is how it should look:

![MovieEdit Form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7dk56v1jm6ow0qgwpuz.png)

**Step 2: Set up data bindings**

Setting up data bindings is much the same as before. Here's the one for `text_box_1`, binding its text property to `self.item['movie_name']`:

![Text Data Binding](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a81eg7yxi73svk2v0llk.png)

In this case, though, notice that there's a W at the right end of the data binding. That `W` stands for [writeback ](https://anvil.works/learn/tutorials/data-bindings/docs/client/data-bindings#two-way-data-bindings)and will show on any property that's user-editable. Writeback defaults to inactive, but if you click the W you can activate it.

![Writeback Active](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dz34n7jo5i6p6b0cqv68.png)

When writeback is active and the user edits the value in the Text Box, Anvil will update the original data binding source with those changes. It's the equivalent of you executing `self.item['movie_name'] = self.text_box_1.text` when the TextBox value changes.

Since our purpose is to allow the user to edit the movie information, we want to enable writeback for all of these editable components. Set up the rest, and then check them in the Form's Data Binding summary. They should look like this:

![Data Bindings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j0pdtmmcf0d3ru3b4jiy.png)

Note that we didn't write any code in the `MovieEdit` Form. That's the value of data bindings, to automate the boilerplate code of assigning values to visual components and then getting the values out when the user makes changes.

**Step 3: Trigger your edit form**

We want to access our `MovieEdit` Form from our main Form. We'll do this by displaying the `MovieEdit` form in an alert every time a user clicks a button.

Add a Button on `Form1`. Set its text to 'Edit movie information' and change its name to edit_button.

![Edit Movie Button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kf9iwpskd1fhj6ndbtri.png)

We want some code to run when this Button is clicked. We'll use [events ](https://anvil.works/docs/ui/components#events)for this. Select the Button and click on 'on `click` event' in the Object Palette. This will open the Editor's ['Split' view](https://anvil.works/docs/editor#form-editor) and automatically create an `edit_button_click` method associated with the button.

![Creating the Click Event](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvnm3pat9qx47hoeu15s.png)

We'll write the code that will run when we click `edit_button` inside this method. First, import the `MovieEdit` Form at the top of the Form:

```
from ..MovieEdit import MovieEdit
```

And then in the `edit_button_click` function itself create an instance of the `MovieEdit` Form:

```
def edit_button_click(self, **event_args):
    editing_form = MovieEdit(item=self.item)
```

When we create the instance of the `MovieEdit` Form, we're going to pass our dictionary of movie information as its `item` property. That will make it available in `MovieEdit` as `self.item`.

Now we're going to display the Form in an [alert](https://anvil.works/docs/client/alerts-and-notifications). We'll set the content of the alert to be `editing_form` and the `large` property to be `True`:

```
def edit_button_click(self, **event_args):
    editing_form = MovieEdit(item=self.item)
    alert(content=editing_form, large=True)
```

Run the app and click the editing button to see the movie information in the text boxes and text area. If any of the information doesn't show up in a component, double check the data bindings.

![Testing the Alert](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mcdj3yfuw7ahys79ccj5.gif)

**Step 4: Read the changed values**

The next step is to get the changed values back into the main Form. We are actually almost there since `MovieEdit`'s writeback data bindings are already changing `Form1`'s `self.item` dictionary. But `Form1` doesn't know that those values have changed, and so doesn't know to rerun the data bindings to update the components.

We need to tell Form1 to update its data bindings after the alert returns. We'll do this with `self.refresh_data_bindings()`:

```
def edit_click(self, **event_args):
        editing_form = MovieEdit(item=self.item)
        alert(content=editing_form, large=True)
        self.refresh_data_bindings()
```

Run the app now and edit the movie information to see it changed in `Form1`!

![Editing Movie Data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnwbfqzu5vlv7pku1h2o.gif)

We can now edit our app's movie data!

## Chapter 3: Storing data in Data Tables

We can now edit our favorite movie data, but because it's stored in a dictionary, it won't persist when the app is re-run. Because of this, you'll usually want to store data in a database when using data bindings.

In this chapter, we'll change our app to store the movie data in a [Data Table](https://anvil.works/docs/data-tables) so that edits to the data will persist between runs of the app. Data Tables are an out-of-the-box option for data storage in Anvil, and they're backed by PostgreSQL.

**Step 1: Create a Data Table**

In the Sidebar Menu, choose Data to open up your app's Data Tables.

![Data Tables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cymgvu3u6gn3ois34vda.png)

Next, click '+ Add Table' to add a new Data Table to the app. Name the table 'movies'.

![Add the Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kzt12bfzov2px0vea5e5.gif)

With the new table selected, you'll see the interface for editing the Data Table. We'll set up our Data Table with 4 columns. We need to add the following columns:

- `movie_name` (a text column)
- `year` (a number column)
- `director` (a text column)
- `summary` (a text column).

We can now copy the data from the `self.item` dictionary and add it to our table.

![Filled Data Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4y1pbltieod079cf7tm.png)

Notice that we've used the same names for the columns as we used for the `self.item` keys, so that we do not need to change our data bindings.

**Step 2: Configure the Data Table**

Data tables live on the server, which is a secure and trusted environment. Client Forms and client code run in the user's web browser, which the user has access to. Sufficiently motivated and knowledgeable users can modify the client code of any web app to make it do anything they'd like it to do, including removing any security checks you might put into client code.

By default Anvil Data Tables are [only accessible from server code](https://anvil.works/docs/data-tables/data-security#permissions) because this is the most secure option. You can see that in the Data Table interface:

![Data Table Security](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/osn5c4s73xthv50s8y5p.png)

You have two other options for client code. You can give client code read access (client code can search this table) or full access (client code can search, edit, and delete). Read access is appropriate for tables where there are no access restrictions needed on who can see data in the table. Full access is almost never appropriate for client code since it allows sufficiently motivated users to bypass all your security restrictions and all your validation code.

We're going to use read access for our table since we only have the one row that we want all the users to be able to read. After making that change the configuration should look like this:

![Data Table Client Reading](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tchqzkdt0y0xrdy1scvp.png)

**Step 3: Read from the Data Table**

Now we need to change `Form1` to use the `movies` Data Table as the source for `self.item` instead of our dictionary.

We can access any Data Table with `app_tables.<data-table-name>`. Since our table only has one row, we want to get the first row from the Data Table into `self.item` in the `__init__` function for `Form1`.

```
class Form1(Form1Template):
    def __init__(self, **properties):
        self.item = app_tables.movies.search()[0]
        
        # Set Form properties and Data Bindings.
        self.init_components(**properties)
```

What `app_tables.movies.search()` returns looks a lot like a Python list, so we can use standard list indexing to pull the first item out of the list. What's stored in the list are data table rows, which look enough like Python dictionaries to be used in `self.item` with data bindings.

You should now be able to run the app and see the information from the data table showing on the main page of your app. Editing doesn't yet work, but that's our next step to fix.

## Chapter 4: Store edits to the Data Table

Because we are not allowing the client to write to our Data Table, we cannot use writeback as we have been.

**Step 1: Update the Data Table**

Instead, we'll use a [server function](https://anvil.works/docs/server) to update the Data Table.

Anvil's [Server Modules](https://anvil.works/docs/server) are a full server-side Python environment. Unlike client code, Server Modules cannot be edited or seen by the user, so we can [trust ](https://anvil.works/docs/security#client-vs-server-code)them to do what we tell them. This is why we'll use a Server Module to write to the Data Table.

For more information about the difference between client and server code, check out [this explainer](https://anvil.works/articles/client-vs-server).

Let's create a Server Module. In the App Browser, click the blue '+ Add Server Module' button underneath 'Server Code'. This will open up a code editor.

![Creating Server Module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/al1u4m3pcbtra4ws0kz3.png)

Our server function will be taking in a dictionary from the client and updating the Data Table with its contents. We'll decorate it with `@anvil.server.callable` so that we can access it from client code. Remember that we're still dealing with just the single row in the Data Table.

```
@anvil.server.callable
def update_movie(movie_data):
    row = app_tables.movies.search()[0]
    row['director'] = movie_data['director']
    row['movie_name'] = movie_data['movie_name']
    row['summary'] = movie_data['summary']
    row['year'] = movie_data['year']
```

Server functions also give us a place to put any data validation we need. In the case of the movie data, we probably don't want to allow any of the fields to be empty.

```
@anvil.server.callable
def update_movie(movie_data):
    if movie_data['director'] and movie_data['movie_name'] and movie_data['summary'] and movie_data['year']:
        row = app_tables.movies.search()[0]
        row['director'] = movie_data['director']
        row['movie_name'] = movie_data['movie_name']
        row['summary'] = movie_data['summary']
        row['year'] = movie_data['year']
```

The exact validation you do depends on your app and the server function, but it's the spot to do last minute validation before you write changes to the Data Table.

**Step 2: Make a copy of the Data Table row**

Switch to the Code view for `Form1` and look at the `edit_click` function.

We can no longer pass `self.item` directly to the `MovieEdit` form, since `self.item` is a read-only Data Table row and writeback will not work with it. What we can do instead is convert the item to a dictionary, effectively making a copy of it. Modify the `edit_click` function to do so.

```
def edit_click(self, **event_args):
        item = dict(self.item)
        editing_form = MovieEdit(item=item)
        alert(content=editing_form, large=True)
```

Writeback data bindings will work fine on the dictionary, since it's no longer a Data Table row, but a dictionary with copies of the values that were in the Data Table row.

**Step 3: Update the Data Table row**

After the alert is closed, we must call the server function to update the Data Table row and pass it the `item` dictionary. We do that by using `anvil.server.call` to call our `update_movie` server function.

```
def edit_click(self, **event_args):
        item = dict(self.item)
        editing_form = MovieEdit(item=item)
        alert(content=editing_form, large=True)
        anvil.server.call('update_movie', item)
```

**Step 4: Update `self.item`**

Now that the server function has been called, we must update the main Form's data. We'll reset `self.item` by getting the now updated row from our Data Table, then we'll use `self.refresh_data_bindings()` to trigger the Form to update the text property of its components:

```
def edit_click(self, **event_args):
    item = dict(self.item)
    editing_form = MovieEdit(item=item)
    alert(content=editing_form, large=True)
    anvil.server.call('update_movie', item)
    self.item = app_tables.movies.search()[0]
    self.refresh_data_bindings()
```

Now, edits to the app will persist when you re-run the app. All users will see the edits that any users make.

Run the app, edit the movie information, and then stop the app and verify the data in the Data Tables has changed.

![Data Tables Changing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6hugk77funldkrnk54k.gif)

And that's it! We have built a simple app to showcase data for your favorite movie. From here, you could extend your app's functionality, for example by allowing users to have their own separate favorite movies.

## What's Next?

Head to the [Anvil Learning Centre](https://anvil.works/learn/tutorials?utm_source=dev_to_data_binding) for more guided tutorials, or head to our [examples ](https://anvil.works/learn/examples?utm_source=dev_to_data_binding)page to see the variety of apps you can build with Anvil.