If you are distributing your widget and decide to use the deferred loading technique (preferred), you can remove all references to the WidgetManager and the register model/view calls (see the Python section below for more information).
In 2.0 require.js was used incorrectly, that has been fixed and now loading works more like Python’s import. Requiring widgets/js/widget doesn’t import the WidgetManager class, instead it imports a dictionary that exposes the classes within that module:
{
'WidgetModel': WidgetModel,
'WidgetView': WidgetView,
'DOMWidgetView': DOMWidgetView,
'ViewList': ViewList,
}
If you decide to continue to use the widget registry (by registering your widgets with the manager), you can import a dictionary with a handle to the WidgetManager class by requiring widgets/js/manager. Doing so will import:
{'WidgetManager': WidgetManager}
Don’t rely on the IPython namespace for anything. To inherit from the DOMWidgetView, WidgetView, or WidgetModel, require widgets/js/widget as widget. If you were inheriting from DOMWidgetView, and the code looked like this:
IPython.DOMWidgetView.extend({...})
It would become this:
widget.DOMWidgetView.extend({...})
Custom models are encouraged. When possible, it’s recommended to move your code into a custom model, so actions are performed 1 time, instead of N times where N is the number of displayed views.
Generally, custom widget Python code can remain unchanged. If you distribute your custom widget, you may be using display and Javascript to publish the widget’s Javascript to the front-end. That is no longer the recommended way of distributing widget Javascript. Instead have the user install the Javascript to his/her nbextension directory or their profile’s static directory. Then use the new _view_module and _model_module traitlets in combination with _view_name and _model_name to instruct require.js on how to load the widget’s Javascript. The Javascript is then loaded when the widget is used for the first time.
In the IPython 2.x series the only way to register custom widget views and models was to use the registry in the widget manager. Unfortunately, using this method made distributing and running custom widgets difficult. The widget maintainer had to either use the rich display framework to push the widget’s Javascript to the notebook or instruct the users to install the Javascript by hand in a custom profile. With the first method, the maintainer would have to be careful about when the Javascript was pushed to the front-end. If the Javascript was pushed on Python widget import, the widgets wouldn’t work after page refresh. This is because refreshing the page does not restart the kernel, and the Python import statement only runs once in a given kernel instance (unless you reload the Python modules, which isn’t straight forward). This meant the maintainer would have to have a separate push_js() method that the user would have to call after importing the widget’s Python code.
Our solution was to add support for loading widget views and models using require.js paths. Thus the comm and widget frameworks now support lazy loading. To do so, everything had to be converted to asynchronous code. HTML5 promises are used to accomplish that (#6818, #6914).
In IPython 3.0, widgets can be instantiated from the front-end (#6664). On top of this, a widget persistence API was added (#7163, #7227). With the widget persistence API, you can persist your widget instances using Javascript. This makes it easy to persist your widgets to your notebook document (with a small amount of custom JS). By default, the widgets are persisted to your web browsers local storage which makes them reappear when your refresh the page.
Here is a chronological list of PRs affecting the widget and comm frameworks for IPython 3.0. Note that later PRs may revert changes made in earlier PRs: