ipython/ipython — pull request #6463 by SylvainCorlay (2014-09-14 00:38:03+00:00)
Title: Bulk update of widget attributes

This PR is an optimization in the way widget attributes are updated from the Python side.
The motivation is the following: Let us say that `chart` is a widget, which has a `width` and a `height` attribute among others. In the JavaScript implementation of the widget, we may have:
```JavaScript
render: function() {
// ...
this.model.on("change:width change:height", this.update_layout, this);
// ...
}
```
Then, in the Python side, if one wants to change both width and height at once:
```Python
with chart.hold_sync():
chart.width = 1000
chart.height = 500
```
With the current behavior, the `update_layout`, which essentially redraws the entire chart is called twice.

This PR is meant to allow one to do the following in the implementation of the widget:

```JavaScript
render: function() {
// ...
this.model.on_bulk_change(["width", "height"], this.update_layout, this);
// ...
}
```

A way to test this in a notebook is the following:
In a Python cell
```Python
from IPython.html.widgets import Widget, DOMWidget
from IPython.utils.traitlets import Unicode, Bool
from IPython.display import display
class TestWidget(DOMWidget):
_view_name = Unicode('TestWidget', sync=True)
a = Bool(False, sync=True)
b = Bool(False, sync=True)
```
```JavaScript
%%javascript
var TestWidget = IPython.DOMWidgetView.extend({
render: function() {
this.model.on_bulk_change(['a', 'b'], function() {
console.log('bulk change');
});
this.model.on("change:a change:b", function() {
console.log('normal change');
});
},
});
IPython.WidgetManager.register_widget_view('TestWidget', TestWidget);
```
```Python
wid = TestWidget()
display(wid)
with wid.hold_sync():
wid.a = True
wid.b = True
```
You will see that `bulk change` is displayed only once while `normal change` is displayed twice in the JavaScript console.