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.
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
},
});
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
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.