I am interested in the current best practices and solutions for using the data driven documents library with two-way AJAX
data bindings. More specifically I am wondering how d3 should be best integrated with libs supporting two-way data bindings such as Angular or Knockout.
The obvious conflicts that arise stem from the fact that d3 and the AJAX
libs are both inserting data to the DOM
, which basically means that one has to wrap the other.
D3 is data driven. The data() function is used to join the specified array of data to the selected DOM elements and return the updated selection.
D3 data selections. Data selections are the core of D3's data binding API. A data selection is created by diffing an array of data against a DOM selection. This example selects . app-user DOM elements and matches them to an array of user data.
In a two-way binding, the data flow is bi-directional. This means that the flow of code is from ts file to Html file as well as from Html file to ts file. In order to achieve a two-way binding, we will use ngModel or banana in a box syntax.
D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to create an interactive SVG bar chart with smooth transitions and interaction.
You were worried about the data inserted to the DOM. This are some of the properties added:
__data__
, __onmouseover.force
, __onmouseout.force
, __onmousedown.drag
, __ontouchstart.drag
, __onmousedown
value
, type
, version
, align
, ng339
So there's no colisions and no need to wrap one into another. You can test this using Object.keys(SOME_DOM_ELEMENT);
and Object.keys(SOME_DOM_ELEMENT.__proto__);
This is how you assign data to D3js:
d3selector.data( myNameSpace.myDataObject );
And this is my data binding approach using watch: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
d3selector
myNameSpace.watch('myDataObject', function (id, oldval, newval) {
d3selector.data( newval );
return newval;
});
This way, everytime you change myNameSpace.myDataObject
the data used by D3js will be updated too. But this will only work on Firefox.
There's an answer in this question Angular + d3.js: Data binding with SVG text attr? that explains how to do it using $watch.
Is similar to the Firefox watch:
directive('myDirective', function ( /* dependencies */ ) {
// Imagine your $scope has myDataObject
$scope.$watch('myDataObject', function (newVal, oldVal) {
d3selector.data(newVal);
});
}
Now everytime you change myDataObject
in the $scope
the data of D3js will be updated too.
Here is an example of two way data binding using polymer: http://bl.ocks.org/psealock/a4f1e24535f0353d91ea you can test it here: http://bl.ocks.org/psealock/raw/a4f1e24535f0353d91ea/
As you can see in refreshChart
the binding is not really being used. Instead, on the event triggered when the data changes, D3js loads the new data:
this.g.data(this.pie(this.data));
D3js is not prepared to listen for changes on the data, unless you use the data
method. That's why the already rendered data will not change.
If in the future data bindings were implemented, I guess there will be a new method on selection
:
selection.update - return placeholders for updated elements.
similar to the current enter
and exit
:
selection.enter - returns placeholders for missing elements.
selection.exit - returns elements that are no longer needed.
removing the need to create refresh functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With