Data Bindings to simple Object dictionary or list

I am trying to update data in a repeating panel that is linked to a list within a dictionary in a simple object. I am completely lost on how to do this. I can update the values on the client-side, but they do not update the data in the database?

I have tried doing a list update, but have no idea how to extract the index of the current repeating panel item, so it updates the whole simple object field with only the data from the repeating panel, deleting all the other dictionary data outside of that list item.

I want to store the data in a single field such that I don’t have to create a plurality of tables and fields to hold this data, what is the best way to manipulate simple object data within a repeating panel?

Welcome, @steve1!

“Best” is in the eye of the beholder. Why don’t we start with something concrete, like:

  1. The columns of your RepeatingPanel?
  2. The shape, or structure, of your Simple Object?

Do you have any flexibility with them, or are they pre-set by someone else?

What is the correspondence between the two?

I am able to be flexible! Pretty new with Anvil, so forgive me if this is really simple and I’m totally missing it.

Here is a quick outline of what I have going on:

simple Object field data:

{
  "sites": [
    {
      "index": 1,
      "site_name": "Aqua Living Stores - Iowa",
      "address_1": "3410 100th Street",
      "address_2": "",
      "city": "Urbandale",
      "state": "Iowa",
      "zip_code": "50322"
    },
    {
      "index": 2,
      "site_name": "Aqua Living Stores - Minnesota",
      "address_1": "7111 Stillwater Boulevard North",
      "address_2": "",
      "city": "Oakdale",
      "state": "Minnesota",
      "zip_code": "55129"
    }
  ],
  "also_serving": [
    {
      "index": 1,
      "region": "Kansas"
    },
    {
      "index": 2,
      "region": "Nebraska"
    },
    {
      "index": 3,
      "region": "North Dakota"
    },
    {
      "index": 4,
      "region": "South Dakota"
    },
    {
      "index": 5,
      "region": "Wisconsin"
    }
  ]
}

It the repeating panel, I am displaying each site from the “sites” list. I recently put the “index” in as a work around to enter the data into the table by using a for loop to search for that particular item within the list then do an update on the whole dictionary before updating the field. Although this works I feel that I over complicating the process?

Yes, the way your information is structured, you should be able to plug it in directly to your Data Grid. The Grid should update the data in-place, i.e., in your SimpleObject. The Anvil folks designed all these parts with that in mind. (Brilliant, guys!)

To make this work, assuming that your SimpleObject is named so:

  1. You should bind (or assign) your Data Grid’s items (list) to so['sites'].
  2. Your RepeatingPanel fields should be bound to item['site_name'], item['address_1'], or whichever fields you actually want visible.

With these settings, the Data Grid (and its Repeating Panel instances) should be able to write the end-user’s edits directly back to the list of dicts that is so['sites'].

Tip: when listing Python constructs here, such as program code, dicts, or lists, you can (should) place ``` on a line by itself, before and after the construct. This displays the actual indentation, which is critical to the meaning of your code.

1 Like

If you have explicit “Save” and “Cancel” buttons, then I would change this slightly, so that both can work as expected. (This is probably of general interest, so I’ll add it here anyway.)

The key is to use a temporary list in place of the real one. That way, if the user Cancels, the original remains unchanged.

  1. from copy import deepcopy
  2. self.edit_buffer = deepcopy(so['sites'])
  3. bind the Data Grid to self.edit_buffer instead of directly to so['sites']
  4. On Save, re-assign so['sites'] = self.edit_buffer, and write it back to the database.
  5. On Cancel, leave so['sites'] unchanged.

Here is the code in my main form:

from ._anvil_designer import AccountTemplate
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



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

    # Any code you write here will run when the form opens.
    from .. import data_cache
    
    self.user = data_cache._user
    
    if not self.user:
      user = data_cache.require_user()
      
      
    self.item = anvil.server.call('get_account_data', self.user)

    self.repeating_panel_locations.items = self.item['location_details']['sites']

The data bindings in the main form are set for the repeating panel are as such:

self.item['location_details']['sites']

Here is the code for my repeating panel form, I have the text box for ‘state’ hidden so that I can update it with a dropdown:

from ._anvil_designer import SitesTemplate
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

from ...lists import states


class Sites(SitesTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    
    # Any code you write here will run when the form opens.
    self.drop_down_states.items = states
    self.drop_down_states.selected_value = self.text_box_state.text
    
  def drop_down_states_change(self, **event_args):
    self.text_box_state.text = self.drop_down_states.selected_value

The data bindings on the repeating panel form are set as an example:

self.item['site_name']

Also, after understanding how this should work, I would be interested in knowing how to bind it explicitly with a “SAVE” / “CANCEL” operation.

The key for Save/Cancel is to use a temporary list in place of the real one. That way, if the user Cancels, the original remains unchanged.

  1. from copy import deepcopy
  2. Create the temporary list: self.edit_buffer = deepcopy(self.item['location_details']['sites'])
  3. bind the Repeating Panel’s enclosing Data Grid (not the Repeating Panel!) to the copy, i.e., to self.edit_buffer.
  4. Bind each of the Grid’s columns to its corresponding dict entry, by name (key). For example: image
    So your Keys would be site_name, address_1, etc.
  5. At run-time, the Data Grid will bind each instance of the Repeating Panel to its own list element for you, so you should not bind the Panel itself.
  6. Within the Repeating Panel, bind each editable field to its value by name (key): item[ key ] For example:image
  7. On Save, re-assign so['sites'] = self.item['location_details']['sites'] , and write it back to the database.
  8. On Cancel, leave self.item['location_details']['sites'] unchanged.

I hope this clarifies matters!

I don’t have a data grid in my form? Do I need to put the repeating panel inside a data grid?

That’s the recommended method. It lets the Data Grid do so much of the work for you!

Nearly every related example, Tutorial, and bit of documentation from the last two years has used a Data Grid. If my experience is any indication, it should fit your case very well.

I’ve tried adding a Data Grid and still am having NO luck! Is there some other way to get assistance?

Absolutely! Anvil’s Search feature
image
is right at the top of this page. And it searches not just the documentation, but the examples, tutorials, and the forums!

Please give it a try; you’ll be amazed at the wealth of information available.

Data Grids do have their own Tutorial, and it’s much better than I can do on my own.

1 Like

@p.colbert
I understand your idea , but i have an issue when delete item in Repeating Panel and how to update list state without index ?

Welcome to the Forum!

It’s hard to give useful help when we have so little to start with!

Your question deserves your starting a new Q&A topic, with a new title, and with pertinent details of the problem, as you’re experiencing it.

When you start that new topic, the Forum will give you a template, to help you pull that information together into a coherent story of the problem. The goal is to get us just enough relevant information to actually help you, with as little effort on your part as can be managed.