From our last post we ended with a more complex object. Creating multiple DIVs. But what if some data already exists on the page? Can we update it? Why, yes we can! However, unless we don't care which elements we want to be updated, we need to give the script a little more information. Let's add a "key", not unlike a primary key in a relational database. We tell the data() method how to associate data. We do this by passing an inline method to the data() method after the data itself:
data(ds, function(d){return d.key;})
So for each item "d" in the dataset "ds" we return its "key" element and from then on use that to reference the elements on the page.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
</script>
</body>
</html>
View on Plunker - Ex 4.1
In this case, not much has changed to the naked eye, we just added a key. But if we go at the data again. We can make specific changes.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
// A new array with 1 element with a matching Key
var updated = [ {"id":2,"name":"Freddy","Age":45} ];
d3.select("body")
.selectAll("div")
.data(updated,function(d){return d.id;})
// Since we just want to update, we don't need the enter()
// list, instead, by default the data() method gives us
// access to the existing data/element joins
// we just get the matching exiting list and can set
// its text.
.text(function(d){ return d.name});
</script>
</body>
</html>
In the second part of the script, only the element bound with the key of 2 is updated. Without the key, the first element (John) would have been updated (to Freddy) because the key is just sequential.
What about if that second array (with the updated item) is all you want to show up? Then we have access to another set of data, the exit() list. We can then operate on the elements in the selection that are not included in the data.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
var updated = [ {"id":2,"name":"Freddy","Age":45} ];
d3.select("body")
.selectAll("div")
.data(updated,function(d){return d.id;})
.text(function(d){ return d.name})
// Get the elements from the selection that are not included
// in the data set and operate on them. In this case turn
// them red
.exit()
.style('color','red')
</script>
</body>
</html>
View on Plunker - Ex 4.2
We could also make use of the remove() method to get rid of the elements that are in the exit() selection.
data(ds, function(d){return d.key;})
So for each item "d" in the dataset "ds" we return its "key" element and from then on use that to reference the elements on the page.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
</script>
</body>
</html>
View on Plunker - Ex 4.1
In this case, not much has changed to the naked eye, we just added a key. But if we go at the data again. We can make specific changes.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
// A new array with 1 element with a matching Key
var updated = [ {"id":2,"name":"Freddy","Age":45} ];
d3.select("body")
.selectAll("div")
.data(updated,function(d){return d.id;})
// Since we just want to update, we don't need the enter()
// list, instead, by default the data() method gives us
// access to the existing data/element joins
// we just get the matching exiting list and can set
// its text.
.text(function(d){ return d.name});
</script>
</body>
</html>
In the second part of the script, only the element bound with the key of 2 is updated. Without the key, the first element (John) would have been updated (to Freddy) because the key is just sequential.
What about if that second array (with the updated item) is all you want to show up? Then we have access to another set of data, the exit() list. We can then operate on the elements in the selection that are not included in the data.
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var ds = [
{"id":1,"name":"John","Age":22},
{"id":2,"name":"Fred","Age":45},
{"id":3,"name":"Ann","Age":32}
];
d3.select("body")
.selectAll("div")
.data(ds,function(d){return d.id;})
.enter()
.append("div")
.text(function(d){ return d.name});
var updated = [ {"id":2,"name":"Freddy","Age":45} ];
d3.select("body")
.selectAll("div")
.data(updated,function(d){return d.id;})
.text(function(d){ return d.name})
// Get the elements from the selection that are not included
// in the data set and operate on them. In this case turn
// them red
.exit()
.style('color','red')
</script>
</body>
</html>
View on Plunker - Ex 4.2
We could also make use of the remove() method to get rid of the elements that are in the exit() selection.
Comments
Post a Comment