How to trigger a redraw of an ObjectSelector?

I have a Panel app that has an ObjectSelector which is built off of an existing dictionary. The app has a button you can click to add additional items to the dictionary that immediately appear in the dropdown.

This is a simplified version:

class Test(param.Parameterized):
    
    store = param.Dict({'one': 1, 'two': 2})
    
    selector = param.ObjectSelector()
    
    trigger = param.Integer(default=1)
    
    def __init__(self, **params):
        super().__init__(**params)
        self.update_selector()
    
    def update_selector(self, key=None):
        print('update selector')
        self.param.selector.objects = self.store
        if key:
            self.selector = key
        self.trigger += 1
        
    def on_click_add(self, event):
        num = len(self.store) + 1
        self.store[f'{num}'] = num
        self.update_selector(f'{num}')
    
    @param.depends('trigger', watch=True)
    def panel(self):
        print('redraw')
        # create add button
        button_add = pn.widgets.Button(name='\u002B', width=20)
        # link button to callback
        button_add.on_click(self.on_click_add)
        
        return pn.Row(self.param.selector, button_add)
    
app = Test()
app.panel()

The button successfully adds items to the store dictionary and adds objects to the selector. However, it doesn’t redraw the selector. Based on the print statements, it DOES redraw the panel method, but the selector doesn’t change. If you manually redraw the selector (in another jupyter cell, e.g), the selector is updated as it should.

Questions:

  1. Why doesn’t the redraw of the panel method cause the selector to be redrawn?
  2. How can I get rid of the need for trigger and depend on variables that already exist? @param.depends('store', watch=True) doesn’t work.
1 Like

change your last line by:

pn.panel(app.panel)

or change your class using this:

    @param.depends('trigger', watch=True)
    def layout(self):
        print('redraw')
        # create add button
        button_add = pn.widgets.Button(name='\u002B', width=20)
        # link button to callback
        button_add.on_click(self.on_click_add)
        
        return pn.Row(self.param.selector, button_add)
    
    def panel(self):
        return pn.panel(self.layout)

Oh wow, that makes complete sense, but I don’t think I’d have ever picked up on that! Thank you!!