How to remove an item from a DataGrid

The RowTemplate forms inside a DataGrid have an unlink button that deletes the item from the DataGrid and its row from the database. The button code is this:

  def unlink_click(self, **event_args):
    anvil.server.call('delete_row', self.item)
    self.remove_from_parent()

The repeating panel has been populated with something like repeating_panel.items = app_tables.locked_files.search() (the real code does a round trip, some sorting and filtering, but this gives the idea).

The server function delete_row deletes the row from the database.

When I click on the unlink button:

  • self.remove_from_parent() removes the form from the repeating panel
  • anvil.server.call('delete_row', self.item) deletes the row from the database
  • repeating_panel.items still contains the search iterator that doesn’t know that the row has been deleted

So, after removing a few items everything looks good because the rows disappeared from both the UI and the database, but as soon as I click on a pagination button it crashes because the iterator tries to render the missing row.

I tried with repeating_panel.items.remove(row), but it doesn’t work.

Is there a way to keep the lazy loading search iterator while being able to remove any arbitrary item?

Or do I need to create my own Portable that behaves like the iterator created by table.search, but implements the remove method?

I had a similar problem a few times but used a totally different solution to solve it without using
self.remove_from_parent()

I created a module to be accessible across rows and forms at the base level of the app called x_form (or whatever you want, you probably already have done this before)
In it is just an initialization of a list:
hide_items_list = []

At the top of the row template code for the data grid:
from Your_App_name import x_form

In the __ init __ of the RowTemplate:
self.visible = not self.item in x_form.hide_items_list

In your unlink button:

#you have to put this before the call to delete the row from the database
x_form.hide_items_list.append(self.item)
self.visible = False
#your call to delete
anvil.server.call('delete_row', self.item)

This will both delete the row from the source of the app building it into the grid, and stop it from rendering, without attempting to iterate over a component that has been removed using .remove_from_parent()

The only janky part is that is until you rebuild the data grid, if you page back and forth using the pagination button as described, the number of rows displayed will be missing however many you deleted.
For example if you have a page set to display 10 items, only 9 will show until the entire grid is rebuilt, it seems like it uses the count of components, even if they are hidden.

1 Like

It works like this because the pagination uses self.items, not the forms inside the repeating panel.

Your trick solves the crash problem. I may use it as a temporary solution. I will eventually try to use a lazy loading Portable.

I tried creating my own lazy loading class long time ago and failed.

Now Meredydd says it should be possible, so I will give it another try (eventually).

1 Like