Tabulator - with anvil components

A small update on this since i’ve been using it on a project and have enhanced the custom formatters feature - you can now use a function that returns a component…


inspired by @meredydd original datagrid show and tell (before data grids existed in anvil…)


simple example

set the column formatter to a function that returns a link with a click_event.

self.columns = [
...
    {'title':"Name", 'field':'name', 'formatter': self.name_foramtter}

...
]

# must include a row argument and **kwargs
def name_formatter(self, row, **params):
  def link_click(**event_args):
    print(row)
  link = Link(text = row['name'])
  link.set_event_handler('click', link_click)
  # return a component
  return link


more in-depth

My use case was a cell that had 5 status icons.
when the status icon was clicked it would then update the database and change color accordingly…

class Form(FormTemplate):
  def __init__(self, **properties):
    self.columns = [
        ...
        {'title':"Status", 'field':'status', 'formatter': self.status}
        ...
    ]

self.status is a function that returns a flow_panel with links


  icons    = ['fa:ban', 'fa:exchange',  'fa:database',   'fa:envelope', 'fa:check']
  spacing = dict(spacing_above='none', spacing_below='none')
  
  def status(self, row, **kwargs):

    def status_clicked(sender, **event_args):
      for link in links[sender.tag+1:]:
        link.foreground = "theme:Gray 300"
      for link in links[:sender.tag+1]:
        color = f"theme:{sender.tag}" # colors defined in theme
        link.foreground = color
      if row['status'] != sender.tag:
        row['status'] = sender.tag
        self.tabulator.update_row(row['id'], row)
        anvil.server.call_s('update_row', row)

      
    panel = FlowPanel(**self.spacing)
    links = []
    current_status = row['status']
    current_link = None
    for i,icon in enumerate(self.icons):
      link = Link(icon=icon, tag=i, **self.spacing)
      panel.add_component(link)
      links.append(link)
      link.set_event_handler('click', status_clicked)
      if current_status == i:
        current_link = link
    status_clicked(sender=current_link)
    
    # return a component to be rendered for the cell
    return panel


This could also be down with a form and databindings - but sometimes I find databindings a little slow and it can be nice to just do something in code…

The result:

Kcc1bWu6Kd

6 Likes