How to display data searched from server table into a client form with repeating panel

Hello here again (with sincere apology for my last ‘bombed’ topic)

After signing for a free account and going through the tutorials, I am able to do something worth my while. I am still a newbie though so please understand if my question is a bit off the rails.

Here’s what I have been doing and where i am stuck. I created a server function to search a database (code below). Search is OK but it is displaying the found data in a client-side form that i am stuck.

Note: the function below to search server table; search_page is <class ‘dict’> that I pulled out from one search form.

def search_button_click(self, **event_args):
    search_page = {}
    submit_clicked = alert(
      content= Userpage(item = search_page),
      title="Search data",
      large=True,
      buttons=[("Submit", True), ("Cancel", False)],
    )

 lst_found = anvil.server.call('search_records', search_page)

Above line: called the server module function to search the table
The server returns a data row (sample below) that matches the search_page argument:


[[{'complex': 'Campinas Real Estate', 'street': '455 Campinas Street', 'country': 'Peru', 
'remarks': '', 'email': 'cvh101@gmail.com', 'lease': 'none', 'town': 'Campinas', 'type2': 'farm'}], 1]

Note: lst_found is <class ‘list’>

To view the above data on the client side, I have a RepeatingPanel (‘found_panel’)
with item template linked to a form (ViewForm) with the same columns as the data table
in the server.

I tried the below function to load the lst_found but it doesn’t work. I get the error
that the form where it resides does not have the attribute ‘load_foundview’:


def load_foundview(self):
   self.found_panel.items = lst_found```

Could I get any suggestion here how I could display the found data in a
form view with repeating panel?
Thank you.
PS: sorry for the ugly format; I am still learning how to post a neat one here…sigh.

That’s an odd error that suggests something more is wrong than just what you’re trying to do. Can you share a clone link? Anvil Docs | Cloning Apps

Keep in mind that sharing a clone link shares everything in the master branch and everything that’s in the data tables, so if there’s anything sensitive there you might want to create a new app just demonstrating the issue you’re having and share a clone link to that.

Thanks for the feedback.

Right now, I can’t share a clone link. In time, when I feel that data items are secure enough, I won’t mind doing that.

Meanwhile, though I am not sure if it’s causing any problem, I notice that switching between classic designer and the new designer sometimes hang. Has anybody in this forum ever reported that yet?

Just a thought on my problem.

It’s probably the data type that is stalling me. The data from server is <class ‘dict’> but the found data that I am passing to the client form is of <class ‘list’>. I am now testing if passing the found data as a single dict might work. Will give an update here after testing.

No luck on converting the list of dicts to a single dict in the server module and passing to a client-side form. Problem stays.

However, on trying other ways I ran into another problem which I cannot resolve. Here’s the error:

Exception: Data Binding update failed with 8 errors.
Did you initialise all data binding sources before initialising this component?
Error binding text of complex_label to self.item[‘complex’]: string indices must be integers, not str. I had it as ‘text’ when binding the component.

Can’t understand why it’s now looking for integer as index. :thinking:

I fixed the error binding problem but I am back to this error which seems to be common. I am still looking for solution but here is that ubiquitous error:

AttributeError: 'HomeUser' object has no attribute 'refresh_foundview'

Help please if anybody has a nifty solution. Thanks.

The description you give may not be enough for us to see the error. Please share a clone link, so we can see the whole app. (We will see also the content of the data tables, so please remove any sensitive data.)

Here is what this does:

  • create search_page with an empty dictionary
  • shows an alert with the Userpage form. The form is created using the empty dictionary search_page
  • calls the server function and stores the returned value in the variable lst_found, which is immediately destroyed

I don’t know what the Userpage form does, but I’m guessing it will show nothing interesting.

Sorry, it’s my bad the way I assigned variable names that can throw peope off.

The variable ‘search_page’ is actually a dict, not a page or anything like that. It stores a single dict that contains the dict values that I, as a user for instance, would like to check if there are matching dicts in the data rows (also dicts) of the server table.

The Userpage is the page view (or form) where the dict ‘values’ to be search are entered and stored in the variable ‘search_page’.

lst_found can actually be printed (as a single dict after list conversion) at the client side by statement 'anvil.server.call(‘search_records’ so I assume it is not destroyed. I maybe wrong but I assume the value of lst_found is still available at the client side if it can be printed in the console.

Let me know if there’s something afoot in the above.

Thank you.

Ok so you are using the mutable argument search_page to get the result back from the form. That’s perfectly ok, I didn’t think about it because I rarely do it.

Then, rereading you original post, I see another thing a little suspicious:

That is a list, but can’t be used in a repeating panel, because it contains a list of dictionaries and a number. Perhaps you want to assign the first item of that list to items?

Again, I’m trying to read the few lines of code you pasted and reverse engineer what you are doing on the lines I don’t see. A clone link would save my time and increase the chances for you to get an answer.

Thanks for the insight.

Yes, the lst_found was originally a list of dicts which I had converted to a single dict in the server side before passing back to the client.

Again, sorry for the poor choice of variable name. In the most recent version, I did name the variable as d1_found after converting lst_found to imply that it is now a single dict.

I am revising the table to remove items like email etc before reposting an app link. That way, I can address the existing issue here as well as the abnormal designs behavior which I posted separately.

Thank you for hanging on with my problems. I greatly appreciate it.:pray::+1:

I am now preparing a clone to post here which I will post shortly.

Meanwhile, when testing for possible errorr, I ran across this one:

[An internal error has occurred] - see browser console for more details: TypeError: Cannot read properties of undefined (reading 'targetType') at t.createFromTemplate (https://anvil.works/runtime-new/runtime/dist/designer2.bundle.js sha=33b1410eba5978d415ed:28:34999) at HTMLDocument._ (https://anvil.works/runtime-new/runtime/dist/designer2.bundle.js?sha=33b1410eba5978d415ed:608:23556)

The data row found in the data table is originally a list of dicts which was converted to a single dict to send back to the client side. Does the TypeError mean the single dict is the wrong data type to pass to self.found_panel.items? Could going back to the original list of dicts worth a try?

Hi.

Here’s a copy of the link to a modified app…basically same app structure as the one I originally posted here, with a different data table.

Would appreciate help to display the found items in the client-side form.

Here is the copy of the link: Anvil | Login

This is the code you have (with unimportant parts edited out):

  def search_button_click(self, **event_args):
    d1_found = anvil.server.call('search_records', search_brod)

  def show_found(self):
    # Load existing articles from the Data Table and display them in the RepeatingPanel
    self.found_panel.items = d1_found

You are trying to use a local variable d1_found in two functions. Local variables are only good in the function where they’re set.

If you really want that to be used in two functions what you want instead is a class variable, e.g. self.d1_found. Class variables are good throughout all the functions in that class.

But, most commonly you’ll just populate the repeating panel immediately, e.g.:

  def search_button_click(self, **event_args):
    d1_found = anvil.server.call('search_records', search_brod)

    # Load existing articles from the Data Table and display them in the RepeatingPanel
    self.found_panel.items = d1_found

That’s one problem. Another is your server function you call:

@anvil.server.callable
def search_records(search_dict):
  # dict(row)--> explicit conversion into true dict; Anvil's server-based dict is somewhat different)
  rows = [dict(row) for row in app_tables.contactlist.search()] 
  lst_found = []
  row = [(row, lst_found.append(row)) for row in rows if search_dict.items() <= row.items() ]
      
  # below, convert lst_found (list of several dicts) into a single dict
  # note: d1_found = [d1_found.update(x) for x in lst_found] # doesn't work
  d1_found = {}
  for x in lst_found:
    d1_found.update(x)
  # # now, return the single dict of data found in the server
  return d1_found

That always returns an empty list. That could be simplified to just:

@anvil.server.callable
def search_records(search_dict):
  rows = app_tables.contactlist.search()
  return rows

Then, your repeating panel row template never puts the row data into the controls you have on it. There are various ways of doing that, I’ll show you the way to do it in code (databinding is another way, but that would require screenshots):

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

    self.firstname_label.text = self.item['firstname']

You’ll also need to remove the data binding on the firstname_label field since it’s set to self.item[''] which doesn’t exist.

If all of the above is done, the first name at least will show up in the list. You can extend the row template __init__ to set the others, or you can use data binding to set all the fields if you prefer that.

1 Like

Oh great!

I will do as you advised and thank you very much for a great lesson on python coding. :+1::grinning:

Hi.
Following your suggestion as shown below, coupled with removing the bindings, I got the error below:

class FoundView(FoundViewTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    self.lastname_label.text = self.item['lastname']
    self.firstname_label.text = self.item['firstname']
    self.status_label.text = self.item['status']
    self.fratcode.text = self.item['fratcode']```

I got this error for all four items:
Error bindingtext of lastname_labeltoself.item['lastname']:
string indices must be integers, not str.

Actually, I still go the above error even when I use the bindings correcly assigned. 
Any thoughts about  this error?

Your search function is no longer returning a list of dictionaries, but a single dictionary. That doesn’t work for repeating panels. Your search function must return a list of dictionaries (or a list of rows, or a search iterator, or anything else that behaves like a list of dictionaries).

Here is the final solution that I found to print the search items in the server’s data table. The callable function in the server has to be like below:

@anvil.server.callable
def search_member(search_dict):
  # dict(row)--> explicit conversion into accepted dictionary format
  rows = [dict(row) for row in app_tables.contactlist.search()]
  d1_found = [row for row in rows if search_dict.items() <= row.items()]
  return d1_found```

Above codes enbled printing the found items in the 
corresponding client-side form.

Thank you for your help.