Home > Software engineering >  Deleting element with D3 fails
Deleting element with D3 fails

Time:07-14

Deleting dom with D3 fails Hello everyone. I try to use D3 to manipulate doms, which are defined in html ahead of time. Content in html:

<div>
 <p  id="1">James</p>
 <p  id="2">Kate</p>

D3 code:

var div = d3.select('div')
var pp = div.selectAll('p.child');
var ppUpdate = pp.data(dataset, d =>d.id);
var ppexit = ppUpdate.exit();
ppexit.remove();

I use the following data for testing: var data1 = [{ id: 1, name: 'James' }, { id: 4, name: 'Jordan' }];

Error when running to "pp.data": enter image description here

I modified the relevant code to:

var ppUpdate = pp.data(dataset, d => {
   if(d){
     return d.id
   }
 });

There will be no errors. But "ppUpdate.exit();" doesn't return the record I want to delete, instead it returns both records in the html. Further tracing the code execution process, in the "bindKey" function in d3.js, the correct "keyValue" cannot be obtained. enter image description here

Please, how can I complete my function? thanks.

CodePudding user response:

The first argument in selection.data(), that you named d, is the datum of the element. The important information is that the key function is evaluated on the elements and on the data; however, the elements initially have no data bound to them, so the datum is null.

What you want is to get the element's id first:

var ppUpdate = pp.data(dataset, (d, i, n) => d ? d.id : n[i].id);

Notice that because you had an arrow function in your question I cannot use this, so I'm using n[i] to get the element.

Here is the working snippet:

var dataset = [{
  id: 1,
  name: 'James'
}, {
  id: 4,
  name: 'Jordan'
}];
var div = d3.select('div')
var pp = div.selectAll('p.child');
var ppUpdate = pp.data(dataset, (d, i, n) => d ? d.id : n[i].id);
var ppexit = ppUpdate.exit();
ppexit.remove();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>
  <p  id="1">James</p>
  <p  id="2">Kate</p>
</div>

CodePudding user response:

Regarding your first problem:

You are specifying a second argument to the .data function, which will look for value that is bound to the element. But since your p.child has no data bound to it, it will return UNDEFINED

For the second problem, I have done a code snippet for you below. You will have to map the data between existing elements and new data values by specifying what is id and what is the text of p elements.In that way only enter and exit will work fine. Please note that if numder of elements in new dataset increase than no of elements present, you will have to write an enter() method as well. This still works here as 2 elements are already present, so d3 automtaically takes care

var dataset = [{
  id: 1,
  name: 'James'
}, {
  id: 4,
  name: 'Jordan'
}];
var div = d3.select('div')
var pp = div.selectAll('p.child');
var ppUpdate = pp.data(dataset).attr("id", d => d.id).attr("class", "child").text(d => d.name);
var ppexit = ppUpdate.exit();
ppexit.remove();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js" integrity="sha512-MefNfAGJ/pEy89xLOFs3V6pYPs6AmUhXJrRlydI/9wZuGrqxmrdQ80zKHUcyadAcpH67teDZcBeS6oMJLPtTqw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div>
  <p  id="1">James</p>
  <p  id="3">Kate</p>

</div>

  • Related