How to link custom widgets

Hi everyone,

I want to create a custom widget that can access the front-end model of another widget so that they can share functions and data. For example, given:

c1 = MainWidget()
c2 = SubWidget(c1)

How can I handle the c1 argument so that the SubWidget’s front-end model has an attribute like this.mainwidget that points to the MainWidget’s this.model?

Something like this is done in the link widget when they assign two passed models to this.sourceModel and this.targetModel, but I can’t figure out how it is done.

Thanks in advance!

Thanks @zaphod.

This example by @ianhi might provide some pointers: custom-ipywidget-howto/jslink-examples.ipynb at 3721f28c943de769538766cdaf41af02cba244d9 · ianhi/custom-ipywidget-howto · GitHub

1 Like

Thanks @jtp

The example shows how to connect widget attributes after creation. However, I would like to connect them at initialization. Here is one example that I found to work:

On the Python side, I store the main widget id as a traitlet:

@ipywidgets.register
class SubWidget(ipywidgets.DOMWidget):
    
    # ... _view_name etc.
    mainwidget_id = traitlets.Unicode().tag(sync=True)
    
    def __init__(self, mainwidget, **kwargs):
        self.mainwidget_id = mainwidget._model_id
        super().__init__(**kwargs)

On the Javascript side, I use the widget_manager to get the model from the id:

var SubWidget = widgets.DOMWidgetModel.extend({

    // ... defaults: _view_name etc. 

	initialize: function (attributes, options) {
        widgets.DOMWidgetModel.prototype.initialize.call(this, attributes, options);
		let promise = this.widget_manager.get_model(this.get('mainwidget_id'))
		promise.then(this.connect_mainwidget.bind(this));
    },

    connect_mainwidget: function(mainwidget) {
		this.mainwidget = mainwidget
	},

});

If there is a better way, please let me know!

1 Like

Hi @zaphod theres another related example for what you want: custom-ipywidget-howto/connecting-widgets at main · ianhi/custom-ipywidget-howto · GitHub

Though it looks as though you’ve found a very similar solution. The only difference is that I send the model_id as a message rather than as a trait, but I think that both ways are valid. In fact there are likely advantages to using a trait.

If you can think of a way that that example could be improved to make this clearer please feel free to open a PR :slight_smile:

1 Like

Oh actually there is a seemingly substantive difference. You’ve accessed the private attribute _model_id while the version in the linked example uses the public widget.comm.comm_id which may be better future proofed.

2 Likes

Thanks @ianhi, that’s a great example repository!

What do you think could be the (dis-)advantages of using a traitlet?

I think with sending a message the queue of events is a bit more straightforward