I have a select box with some options in it and a input box. I have to filter the values of select box on the basis of the keyword entered in the text box.
JavaScript
function filter() {
var keyword = document.getElementById("search").value;
var select = document.getElementById("select");
for (var i = 0; i < select.length; i++) {
var txt = select.options[i].text;
if (txt.substring(0, keyword.length).toLowerCase() !== keyword.toLowerCase() && keyword.trim() !== "") {
select.options[i].style.display = 'none';
} else {
select.options[i].style.display = 'list-item';
}
}
}
HTML
<div>
<div>
<input type="text" id="search" name="search" style="margin: 10px;width: 165px;" onkeyup="filter()">
</div>
<div>
<select id="select" size="10" style="margin: 10px; width: 165px;height: 170px;">
<option>Cupcake</option>
<option>Cunut</option>
<option>Eclair</option>
<option>Froyo</option>
<option>Gingerbread</option>
<option>Honeycomb</option>
<option>Ice Cream Sandwich</option>
<option>Jelly Bean</option>
<option>KitKat</option>
<option>Lollipop</option>
<option>Marshmallow</option>
<option>Nougat</option>
</select>
</div>
</div>
Is this the right way for this task?
Here is the working code for the scenario.
-
1\$\begingroup\$ Is it possible that it doesn't work with Internet Explorer? If tried your JSFiddle with IE 11 but it doesn't filter the option-items. \$\endgroup\$michael.zech– michael.zech2016年09月05日 06:15:20 +00:00Commented Sep 5, 2016 at 6:15
-
\$\begingroup\$ @mizech yes you are right , its not working in IE , any suggestion to make it work in IE too. \$\endgroup\$Prabhat– Prabhat2016年09月05日 15:51:11 +00:00Commented Sep 5, 2016 at 15:51
-
\$\begingroup\$ IE doesn't support style="display:none;" on <option>tags. \$\endgroup\$Prabhat– Prabhat2016年09月06日 13:02:02 +00:00Commented Sep 6, 2016 at 13:02
-
\$\begingroup\$ Found this: stackoverflow.com/questions/20373558/… If jQuery is an option then have a look at the answer by " Gev ". \$\endgroup\$michael.zech– michael.zech2016年09月06日 13:30:20 +00:00Commented Sep 6, 2016 at 13:30
-
\$\begingroup\$ Have added an answer! \$\endgroup\$michael.zech– michael.zech2016年09月06日 13:40:17 +00:00Commented Sep 6, 2016 at 13:40
4 Answers 4
A good attempt I must say, but there are other ways to achieve this.
Just so you know, select.option
returns an optionCollection
which can be cast to an array using Array.from(select.options)
.
Based on this, you can utilise the filter
pre-defined function for an array object
var optionCollection = Array.from(select.options).filter(x => x.text.toLowerCase().startsWith(keyword.toLowerCase()))
this will get rid of the for..loop
you had. In addition, using filter
function doesn't change the array
but returns a new array with the filtered content.
The result from this can be used to replace the html
of the select
element i.e
$("#select").html(optionCollection)
Note: the above is JQuery
To effectively use the JQuery, you can embed this in a ternary operator
optionCollection.length > 0 ? $("#select").html(b) : $("#select").html(realCollection);
Note: the realCollection
will be the initial select options collection.
I hope this helps
-
\$\begingroup\$ the for loop is way better than the mapping and filter functions \$\endgroup\$PirateApp– PirateApp2018年01月10日 05:53:06 +00:00Commented Jan 10, 2018 at 5:53
I would start by moving the search term into the function definition, to save having to look up the DOM element. So I would change in the HTML
<input type="text" id="search" name="search" style="margin: 10px;width: 165px;" onkeyup="filter(this.value)">
And then have function be defined with keyword as a parameter.
function filter(keyword) {
...
}
The other main change I would make is to use string.prototype.startsWith rather than substring checking, this is more explicit about what is trying to be done, and saves having logic to handle the empty string.
Also, rather than an If statement and then setting style.display, the display is set with either 'list-item' or 'none' with the ternary operator.
This leaves the function as
function filter(keyword) {
var select = document.getElementById("select");
for (var i = 0; i < select.length; i++) {
var txt = select.options[i].text;
var include = txt.toLowerCase().startsWith(keyword.toLowerCase());
select.options[i].style.display = include ? 'list-item':'none';
}
}
A further improvement you might want to look at may include moving the select element selection outside of this function to improve re-use.
-
1\$\begingroup\$ Thanks for the review. I first used
String.prototype.startsWith()
method but in MDN it is mentioned that the method is not supported in all javascript implementation so i used the workaround for that. \$\endgroup\$Prabhat– Prabhat2016年09月03日 19:19:48 +00:00Commented Sep 3, 2016 at 19:19 -
\$\begingroup\$ That's a good point about compatibility. Generally I prefer to use the method in the standards and then polyfil but avoiding that is understandable \$\endgroup\$Eterm– Eterm2016年09月03日 19:40:15 +00:00Commented Sep 3, 2016 at 19:40
I have tried to fix the Internet Explorer problem.
My code is a mixture of the question-code combined with the answer from "Gev" in this StackOverflow question: https://stackoverflow.com/questions/20373558/options-with-displaynone-not-hidden-in-ie
It still doesn't remove the options but they become disabled after leaving the textbox via tabulator key.
The view in Internet Explorer 11:
The adjusted code with jQuery:
function filter() {
var keyword = document.getElementById("search").value;
var select = document.getElementById("select");
for (var i = 0; i < select.length; i++) {
var txt = select.options[i].text;
if (txt.substring(0, keyword.length).toLowerCase() !== keyword.toLowerCase() && keyword.trim() !== "") {
$(select.options[i]).attr('disabled', 'disabled').hide();
} else {
$(select.options[i]).removeAttr('disabled').show();
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div>
<input type="text" id="search" name="search" style="margin: 10px;width: 165px;" onkeyup="filter()">
</div>
<div>
<select id="select" size="10" style="margin: 10px; width: 165px;height: 170px;">
<option>Cupcake</option>
<option>Cunut</option>
<option>Eclair</option>
<option>Froyo</option>
<option>Gingerbread</option>
<option>Honeycomb</option>
<option>Ice Cream Sandwich</option>
<option>Jelly Bean</option>
<option>KitKat</option>
<option>Lollipop</option>
<option>Marshmallow</option>
<option>Nougat</option>
</select>
</div>
</div>
-
\$\begingroup\$ Thanks mizech , but my requirement is to hide the options. \$\endgroup\$Prabhat– Prabhat2016年09月06日 13:44:53 +00:00Commented Sep 6, 2016 at 13:44
-
\$\begingroup\$ You're welcome. Sadly the nearest solution approach I could find. :( \$\endgroup\$michael.zech– michael.zech2016年09月06日 15:19:58 +00:00Commented Sep 6, 2016 at 15:19
-
-
\$\begingroup\$ Indeed. Tried it out and it works like charm on the IE 11 I got here. Heartly congrats ! And thanks for the update. :) \$\endgroup\$michael.zech– michael.zech2016年09月07日 11:33:43 +00:00Commented Sep 7, 2016 at 11:33
My code is based on the question-code of mizech in this StackOverflow question, I add focus() and setInterval() to achieve real time search and show all items when the input box is empty.
The view in IE:
The adjusted code with jQuery:
$("#search-case-name1").focus(
function() {
setInterval(
function() {
var keyword = document
.getElementById("search-case-name1").value;
var select = document.getElementById("case-name1");
if (keyword.length > 0) {
for (var i = 0; i < select.length; i++) {
var txt = select.options[i].text;
if (txt.substring(0, keyword.length)
.toLowerCase() !== keyword
.toLowerCase() &&
keyword.trim() !== "") {
$(select.options[i]).attr('disabled',
'disabled').hide();
} else {
$(select.options[i]).removeAttr(
'disabled').show();
}
}
} else {
for (var i = 0; i < select.length; i++) {
$(select.options[i]).removeAttr('disabled')
.show();
}
}
}, 300);
});
-
1\$\begingroup\$ Could you correct the extreme indentations? \$\endgroup\$t3chb0t– t3chb0t2017年08月01日 06:27:38 +00:00Commented Aug 1, 2017 at 6:27