Databinding Question

I am trying to bind the data I saved in these fields to the textboxes that I am using to save it in the data table.

**In general, what do I need to bind data from the data table to textboxes? Is it even something possible? Looking for some guidance. **

So I can get it to save to the database, but how do I connect it so whenever an update is made in the data table, it reflects it in the textbox?

def save_to_company_database_click(self, **event_args):
    new_company_row = app_tables.company_info.add_row(Company_Name=self.company_name.text,
                                                      Admin=self.admin_textbox.text,
                                                      Email=anvil.users.get_user()['email'],
                                                      Phone_Number=self.phone_number_textbox.text,
                                                      Address=self.company_address_textbox.text, 
                                                      Company_Representatives=self.company_reps_textbox.text
                                                     )
    self.clear_company_fields()``` 

Clone link:
Anvil | Login

Hi Harry,

Take a look at 5 minute CRUD video

3 Likes

You may also want to look at https://pythonanvil.com

2 Likes

Sorry. I just had a chance to look at your 5-minute CRUD video, and go through the example. My question is how do I create a CRUD app as mentioned above without using the Repeated Panel component?

Can I create write-back data binding with labels and textboxes (as the results of a data query)? I know how simple it is to create one with the repeating panel component, but I was wondering if its possible and if so a simple example on how to do it.

Yep, take a look at the last three examples at 5 minute CRUD video - #2 by nickantonaccio . They show you how to update rows of data tables without using repeating panel bindings to make the update: The point in the linked examples is to move update functions to the server, so that edit permissions aren’t given to front end forms, but the same technique can be used anywhere you want to update any values in a data table. Here’s the clone demonstrated in the video examples:

https://anvil.works/build#clone:LVHEEA6QEAROVZKE=SASNRPS7S6YH53QFPNZYBS4Z

Thanks for trying Nick, but your example does not seem to help me understand how to bind data to a data table. I want to bind data to a textbox by using the data binding sidebar.

image

How come it’s not possible to connect to a database like it is possible for repeating panel? I just want to understand the logic behind this as it makes zero sense to me. I am sure there is a way to do it, since it exists. Perhaps I am not explaining myself correctly.

You don’t. The server doesn’t notify your Client code whenever the data changes. You can, however, query the server, on a regular (or irregular!) schedule. This will return the values as of the time you queried them. This technique is called polling. The Timer component can make this a lot easier.

1 Like

I did not realize @Harry_Python asked this question twice, and responded in the other thread :frowning:

1 Like

That’s a bad assumption. It is possible. But it helps to think through how the parts fit together.

In the “to” field above, what Python expression would you enter, to identify the specific database table row and column you want to see displayed?

Hint: imagine that you’ve already found the desired database table row, and have already assigned it to your form’s self.item attribute.

1 Like

Probably it is a bad assumption. I presume it’s possible to do it if it exists in the system, and thus perhaps I am probably not asking the question correctly.

In the “to” field, I would not know how to find that same row of information that it was just entered and saved.

It makes sense that each row a repeating panel is related to 1 of multiple database rows, and bindings relate each widget in a repeating row to one column in each row of the database. That’s a natural corollary. If you don’t want to see multiple rows, I think your may be asking how to do something like this:

https://anvil.works/build#clone:POQAUTEHZ2YSVIKV=NCQOT4O72NVXDSAF3YIBMCFS

1 Like

That’s why I said to assume that self.item had already been assigned to that row. Now all you need to do is name which column contains that value.

The principle is straightforward. The “to” field simply names the value (variable) that will be displayed and updated, as it is known to the containing Form. In the case of a database row r, that’s usually r[column_name], where column_name is the name of the column in the table. By convention, we store the reference to row r in the Form’s item attribute. So it would be accessible to Form code (including data bindings) as self.item[column_name].

This takes full advantage of the semantics of database rows. If r is such a row, then reading r[column_name] fetches the value from the database. Assigning to r[column_name] writes the new value back to the database. And Data Binding does both, behind the scenes, for you.

All that hidden, implicit activity tends to throw people off, the first time they see it. And sometimes, up to the tenth time. (Took me 4 tries!) But you do eventually get used to it.

References here:

1 Like

How would you assign self.item to a row? What throws me off is that in the Repeating Panel, you double click and it asks you which data table it is referencing.

That is where I am thrown off. How do I reference a data table?

Here is the example I want to do.

There is a company_info data table with a row that has a name, address, phone, etc. I do not know how to reference it to that table and have the write back option so when the user enters “Save”, it saves the info to the database and displays it in the textbox.

I think my problem is

  1. How do I identify the row that I just saved?
  2. How do I reference that row and how do I display that row’s data separately in each textbox?

I’m sorry that there are so many moving parts. I don’t see a way to avoid it, though. UI widgets, tables, rows, column values, all are distinct objects, with distinct features and behaviors. For a program to be able to tell them apart, and address each one individually, they all need names, a notation, to refer to each one of them. So you’re asking very good questions!

Thankfully, Anvil has some of the best documentation around. A good place to start would be here: Using Data Tables from Python. This addresses your question directly.

It also collects a lot of related information you’ll use. Including answers to your question 1.

Question 2 is answered by Data Binding, which we’ve been discussing. Strictly speaking, you could do without it. In fact, we did, before Anvil introduced Data Binding. In code, we did things like

self.item = app_tables.people.add_row(Name="Jane Smith",
                                Age=7,
                                Employed=False)
self.textbox_1.text = self.item['Name']

when the Form opened, and

self.item['Name'] = self.textbox_1.text

to save the entered value.

Data Binding is a way to have the textbox do the self.item['...'] assignments for you.

This bit of code starting to make a bit more sense to me. I know I have to rethink everything I wrote thus far in terms of this section of the app. It made sense in my head, but I could not implement it due to the data binding not working as it does in the repeating panel. That makes life so much easier for us new programmers, you probably think we have it so much better than you guys did when Anvil just started. (hehe)

Just for clarity purposes since I am still having difficulty understanding, how does self. item work?

Individually, self means what and .item means what?
My understanding is that the self is an object and the item is well a piece of data.

I got it to work, and understand how it works in terms of what I did, but I just don’t have the experience to figure out how to implement what I want so that is why I ask some newbie questions here to better understand the process.

Very close. self is a specific object. By convention, when Python calls an object’s member functions, it passes the that specific object as the first argument. By convention, the parameter that receives that argument is named self. Hence, in

    def show_form(self, **event_args):
        ...

self is the Form being displayed.

As an object, self can contain its own functions and variables, addressed via “dot notation”, e.g., self.show_form and self.item.

By Anvil’s convention, a Form’s self.item is a Python dictionary, or dictionary-like value, where you can put values for data binding. Since a database table row acts like a dictionary (it uses the same syntax), you can can assign that row to self.item, as I did in my example, and the Data Bindings “just work”. self.item refers to that row, so self.item[column_name] refers to the row’s column value.

2 Likes

Thank you for the lesson, I really appreciate it. That got me thinking that if I can refresh data binding after I save the data, I can use the event handler to display the data back into the text boxes.

to my surprise, all I get is spinning server.

def save_to_company_database_click(self, **event_args):
    new_company_row = app_tables.company_info.add_row(Company_Name=self.company_name_textbox.text,
                                                      Admin=self.admin_textbox.text,
                                                      Email=anvil.users.get_user()['email'],
                                                      Phone_Number=self.phone_number_textbox.text,
                                                      Address=self.company_address_textbox.text, 
                                                      Company_Representatives=self.company_reps_textbox.text
                                                     )
    #self.refresh_data_bindings()
    self.label_company_name.text = self.company_name_textbox.text
    self.form_refreshing_data_bindings()

The above code is supposed to take the inputs and save them in the database that works. It is also supposed to save the company name as a label which worked as well. I think I am using the form self.form_refreshing_data_bindings() incorrectly.

def form_refreshing_data_bindings(self, **event_args):
    self.item = app_tables.company_info.get(Company_Name=self.label_company_name.text)
    self.item['Company_Name'] = self.company_name_textbox.text
    self.item['Admin'] = self.admin_textbox.text
    self.item['Email'] = self.anvil.users.get_user()['email']
    self.item['Phone_Number'] = self.phone_number_textbox.text
    self.item['Address'] = self.company_address_textbox.text
    self.item['Company_Representatives'] = self.company_reps_textbox.text

What I am trying to accomplish is to get the company info name from the label, and populate the textboxes with the appropriate columns.

What I am missing? I can perhaps define another function instead of form_refreshing_data_bindings(self, **event_args): and call it somewhere in the code, but where?

This is the kind of code you would write if you are not using Anvil’s data bindings. All data movement is then your responsibility.

If you are using Anvil’s data bindings, e.g., where self.item['Company_Name'] is entered in the “to” field mentioned earlier, then Anvil is already doing this kind of assignment

    self.item['Company_Name'] = ...
...
    ... .text = self.item['Company_Name']

for you. This is, in fact, the purpose of Anvil’s Data Bindings: doing them behind the scenes, so that you don’t have to write actual code to do it.

The spinner results from this part:

where assigning to self.item triggers the event refreshing_data_bindings, which triggers a call to form_refreshing_data_bindings(). Each time it is triggered, it does another database search, the result of which… ultimately triggers the same search… which triggers the same search… The function never gets a chance to finish!

Generally, assign to self.item only when it has to change to a different row, or when you need to trigger the event refreshing_data_bindings for some other reason.

I am beyond frustrated at this point, and I am clearly missing a lot of information about what I need to happen and what is actually happening. Thank you for your help, Frankly, I couldn’t figure out the solution. The entire problem needs to be rethought.

So I scrapped everything that I did beforehand and figured I can check to see if user’s email matches a record in the company_info data table and if it does pull the data and assign it to the textbox.text fields.

I now getting this error

TypeError: ‘NoneType’ does not support indexing at [admin_haga_system, line 43]

Line 43 is company_info[‘Company_Name’] = self.company_name_textbox.text

if app_tables.company_info.search(Email=anvil.users.get_user()['email']):
      company_info = app_tables.company_info.get(Email=anvil.users.get_user()['email'])
      company_info['Company_Name'] = self.company_name_textbox.text
      company_info['Address'] = self.company_address_textbox.text
      company_info['Admin'] = self.admin_textbox.text
      company_info['Email'] = self.email_textbox.text
      company_info['Phone_Number'] = self.phone_number_textbox.text
      company_info['Company_Representatives'] = self.company_reps_textbox.text
    else: 
      alert("User does not have company profile. Please contact Admin")

** Anvil | Login