Reputation: 611
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
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 option
s 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
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