How to create multiple adjacent nodes per data ele

2019-08-17 21:32发布

问题:

With data like:

var days = ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"];

I need to have the html structure become:

<div>
  <input id="day0" type="checkbox">
  <label for="day0">Sun</label>

  <input id="day1" type="checkbox">
  <label for="day1">Mon</label>
  .... Etc

</div>

Currently my current failed solution is:

var selection = d3.select("div");
var enter    = selection.selectAll("input").data(days).enter()

enter.append("input")
     .attr("type","checkbox")
     .attr("id",function(d,i){ return "day"+i;})

enter.append("label")
     .attr("for",function(d,i){ return "day"+i;})
     .text(function(d,i){return daysAbbr[i];})

Which gives me an incorrect dom of:

<div>
  <input id="day0" type="checkbox">
  <input id="day1" type="checkbox">
   .... Etc
  <label for="day0">Sun</label>
  <label for="day1">Mon</label>
  .... Etc
</div>

How would I go about creating all of these adjacent siblings?

回答1:

You're getting this structure because D3 does a batch processing of sorts with the selections. That is, each operation you perform on a selection is performed on all the elements at once.

In your case, you probably want to use .each(), which allows you to call a function on each element of the selection. The code would look something like this.

var enter    = selection.selectAll("input").data(days).enter();
enter.each(function() {
  selection.append("input");
  selection.append("label");
});

This won't work, as pointed out by @Holger because the .enter() selection doesn't define .each(). The way below will work though.

A better solution in your case would be to encapsulate the elements you want to appear together in another div though. This would allow you to use D3 in a more standard way. The code would look like this.

var enter    = selection.selectAll("input").data(days).enter();
var divs = enter().append("div");
divs.append("input");
divs.append("label");