Ramiro Tormenta
Ramiro Tormenta

Reputation: 611

How to extend number of options in select tag using d3?

Consider a select html tag with only one option that I am using as title or placeholder.

I am using d3.js to render html view and add new elements or options to this tag based on data. This will change a lot, according to different datasets. That's why I am using this method.

However, this method does not return first option or first element in data, as you can see in snippet example. I have three main keys in this example: a, b, and c. And it just added two of them.

If I remove the first option in html view, it works ok. So, what is the best way to extend new options to select tag?

In order to add new, I used this code:

Object.keys(data).map((k) => {
  if (k == 'a') {
    options.push(k)
    options.push(k)
  } else {
    options.push(k)
  }
}) 

However, this would mean knowing what the first element is, and this is not true in most cases.

How can I achieve this result?

var data = {
  'a': {
    'aa': 'aa'
  },
  'b': {
    'bb': 'bb'
  },
  'c': {
    'cc': 'cc'
  }
}

var options = []
Object.keys(data).map(function (k) {
  options.push(k)
})

var selector = d3.select('#myid')
var opts = selector.selectAll('option')
    .data(options.sort())
    .enter()
    .append('option')
    .attr('value', function (d) {
      return d
    })
    .text(function (d) {
      return d
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<select id='myid' name='name' class='form-control'>
  <option disabled selected>Select one item</option>
</select>

Upvotes: 3

Views: 756

Answers (2)

Xavier Guihot
Xavier Guihot

Reputation: 61774

Note: this answer has been edited and corrected based on @GerardoFurtado's in depth explanation of this behaviour.


When using selectAll("option").data(data), as all option elements are selected, the one which is already present in the page (the one hardcoded in the html (<option disabled selected>Select one item</option>)) is also selected.

Thus, when .enter()ing this selection, the first data point considered is bound to this option which already exists in the page, thus skipping inserting the first option from the data.

For the remaining 2 data points to append, as we reached the limit of already existing option elements, then only, new option elements are created.


In this context the most appropriate response would be to use .selectAll(null) as answered by @estebanpdl.

Here is another way to handle this use case (in order to demonstrate the impact of inserting new elements of a certain type when elements of this type already exist in the page). We can select and insert new data options with a specific class to avoid taking into account the existing ones:

var opts = selector.selectAll('option .values')
  .data(options.sort())
  .enter()
  .append('option')
  .attr("class", "values")
  .attr('value', function (d) { return d; })
  .text(function (d) { return d; });

Here is a demo:

var data = {
  'a': { 'aa': 'aa' },
  'b': { 'bb': 'bb' },
  'c': { 'cc': 'cc' }
}

var options = [];
Object.keys(data).map(function (k) { options.push(k) });

var selector = d3.select('#myid');

var opts = selector.selectAll('option .values')
  .data(options.sort())
  .enter()
  .append('option')
  .attr("class", "values")
  .attr('value', function (d) { return d; })
  .text(function (d) { return d; });
<script src="https://d3js.org/d3.v5.min.js"></script>
<select id='myid' name='name' class='form-control'>
  <option disabled selected>Select one item</option>
</select>

Upvotes: 2

estebanpdl
estebanpdl

Reputation: 1233

Instead selectAll option pass null.

var opts = selector.selectAll(null)

var data = {
  'a': {
    'aa': 'aa'
  },
  'b': {
    'bb': 'bb'
  },
  'c': {
    'cc': 'cc'
  }
}

var options = []
Object.keys(data).map(function (k) {
  options.push(k)
})

var selector = d3.select('#myid')
var opts = selector.selectAll(null)
    .data(options.sort())
    .enter()
    .append('option')
    .attr('value', function (d) {
      return d
    })
    .text(function (d) {
      return d
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<select id='myid' name='name' class='form-control'>
  <option disabled selected>Select one item</option>
</select>

Upvotes: 3

Related Questions