Some of the web portals that I maintain use document.createElement to create options in a dropdownlist at runtime. All was well till IE10 but in IE11 or Edge suddenly the performance has gone down dramatically.
I have created a Fiddle: https://jsfiddle.net/nitinph/ej5p65um/
Please run it using both the sets of browsers (IE11/Edge and Chrome/Firefox). You will notice that IE11/Edge takes 10+ seconds whereas Chrome/Firefox takes less than a second.
My question is that is there any alternate way for using document.createElement so that performance is similar in IE11/Edge.
var pTime = document.getElementById("pTime");
var d = new Date();
var n = d.getTime();
var ddl = document.getElementById("TestDDL");
for (var i = 0; i < 5000; i++) {
var opt = document.createElement("option");
opt.text = i;
opt.value = i;
ddl.options.add(opt);
}
d = new Date();
var n1 = d.getTime();
pTime.innerHTML = 'Time: ' + (n1 - n) / 1000 + ' sec.';
<select id="TestDDL">
</select>
<p id="pTime">
</p>
Update: Courtesy #Squint, here are the four alternatives to achieve performance in IE11/Edge:
var ddl = document.getElementById("TestDDL");
console.time("html")
var s = ""
for (var i = 0; i < 5000; i++) {
s += "<option value='" + i + '>' + i + "</option>"
}
ddl.innerHTML = s;
console.timeEnd("html")
clearContent()
console.time("insertAdjacentHTML")
for (var i = 0; i < 5000; i++) {
ddl.insertAdjacentHTML("beforeend", "<option value='" + i + '>' + i + "</option>")
}
console.timeEnd("insertAdjacentHTML")
clearContent()
console.time("frag")
var frag = document.createDocumentFragment();
for (var i = 0; i < 5000; i++) {
var opt = document.createElement("option");
opt.text = i;
opt.value = i;
frag.appendChild(opt);
}
ddl.appendChild(frag);
console.timeEnd("frag")
clearContent()
console.time("direct add")
for (var i = 0; i < 5000; i++) {
var opt = document.createElement("option");
opt.text = i;
opt.value = i;
ddl.options.add(opt);
}
console.timeEnd("direct add")
function clearContent() {
while (ddl.firstChild) {
ddl.removeChild(ddl.firstChild)
}
}
clearContent()
console.time("direct append")
for (var i = 0; i < 5000; i++) {
var opt = document.createElement("option");
opt.text = i;
opt.value = i;
ddl.appendChild(opt);
}
console.timeEnd("direct append")
function clearContent() {
while (ddl.firstChild) {
ddl.removeChild(ddl.firstChild)
}
}
<select id="TestDDL">
</select>
<p id="pTime">
</p>
You could construct the element HTML with strings:
var optionList = ["foo", "bar", "baz"];
var elementHTML = "";
for (var index = 0; index < optionList.length; index++) {
elementHTML += "<option>" + optionList[index] + "</option>";
}
Then create the element and set the innerHTML
var element = document.createElement("select");
element.innerHTML = elementHTML;
This usually offers much better performance as you only call document.createElement() once. Direct dynamic DOM processing, sadly, is usually pretty slow and is recommended against.
Related
So I have this HTML Code/Javascript,
var spellNumber = 0;
function createSpell() {
var spellOption = document.createElement("option");
var spellOption2 = document.createElement("option");
var spellSelect = document.createElement("select");
var spellLabel = document.createElement("label");
var spellEnvelope = document.createElement("p");
spellOption.innerHTML = 'Vanish';
spellOption.setAttribute('value', 'vanish');
spellOption2.innerHTML = 'Teleport';
spellOption2.setAttribute('value', 'teleport');
spellSelect.setAttribute('id', 'spell');
spellSelect.setAttribute('name', 'spell');
spellLabel.setAttribute('for', 'spell');
spellLabel.innerHTML = '<strong>Spell ' + (spellNumber + 1) + '</strong> = ';
spellEnvelope.appendChild(spellLabel);
spellEnvelope.appendChild(spellSelect);
spellSelect.appendChild(spellOption);
spellSelect.appendChild(spellOption2);
document.getElementById("spells").appendChild(spellEnvelope);
spellNumber += 1;
}
createSpell()
function generateYaml() {
var spellCheck = 1;
for (allSpells = 0; allSpells < spellNumber; allSpells++) {
var multipleSpell = $("#spell:contains('Spell " + spellCheck + "')").val();
console.log(multipleSpell);
spellCheck++
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="spells"></div>
<button onClick="createSpell()">Add A Spell</button>
<button id="button" onClick="generateYaml()">Make the Magic Happen</button>
And am trying to retrieve the .value of the <select id="spell"> options. However, the console returns an undefined, instead of vanish or teleport.
Can anyone point me in the right direction for this?
Well:
Id should be unique so I added spellSelect.setAttribute('id', 'spell' + spellNumber); ( + other rows)
Also multipleSpell = $("#spell" + spellCheck).val();
And console.log(multipleSpell); is called only once at the begining -> you should change it to function too
`
var spellNumber = 0;
function createSpell() {
var spellOption = document.createElement("option");
var spellOption2 = document.createElement("option");
var spellSelect = document.createElement("select");
var spellLabel = document.createElement("label");
var spellEnvelope = document.createElement("p");
spellOption.innerHTML = 'Vanish';
spellOption.setAttribute('value', 'vanish');
spellOption2.innerHTML = 'Teleport';
spellOption2.setAttribute('value', 'teleport');
spellSelect.setAttribute('id', 'spell' + spellNumber);
spellSelect.setAttribute('name', 'spell' + spellNumber);
spellLabel.setAttribute('for', 'spell' + spellNumber);
spellLabel.innerHTML = '<strong>Spell ' + (spellNumber + 1) + '</strong> = ';
spellEnvelope.appendChild(spellLabel);
spellEnvelope.appendChild(spellSelect);
spellSelect.appendChild(spellOption);
spellSelect.appendChild(spellOption2);
document.getElementById("spells").appendChild(spellEnvelope);
spellNumber += 1;
}
createSpell()
function generateYaml() {
var spellCheck = 0;
for (allSpells = 0; allSpells < spellNumber; allSpells++) {
var multipleSpell = $("#spell" + spellCheck).val();
console.log(multipleSpell);
spellCheck++
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="spells"></div>
<button onClick="createSpell()">Add A Spell</button>
<button id="button" onClick="generateYaml()">Make the Magic Happen</button>
var multipleSpell = $("#spell:contains('Spell " + spellCheck + "')").val();
More info here.
Edited:
Well, i see you are trying to get all select values. Why not try this?
function generateYaml() {
var spellCheck = 1;
var selects = $("select").each(function (index, element) {
var value = $(element).val()
console.log("The value at index %d is %s", index, value);
spellCheck++
});
}
This way you iterate over all the selects, and get their values inside the loop. Try it here (open the developer console):https://darkcyanpointlessbooleanvalue--parzibyte.repl.co/
I have a dropdown that's populated through a loop. The selected attribute should be added when <%if o.getNextPage()%> is equal to i.
<select id="dropDown" onchange="display(this.value)">
var start = 1;
var end = noOfPages;
var options = "";
for (var i = start; i <= end; i++) {
options += "<option>" + i + "</option>";
}
document.getElementById("dropDown").innerHTML = options;
function display(e) {
document.getElementById("hidden").value = e;
document.invoiceForm.submit();
}
You can add value attribute to the option tag.
As suggested by #3Dos in comments you can use ‘document.createElement‘ without needing to insert raw HTML like this:
var start = 1;
var end = noOfPages;
var options = "";
for (var i = start; i <= end; i++) {
var opt = document.createElement('option');
opt.value = i;
opt.innerHTML = i;
document.getElementById('dropDown').appendChild(opt);
}
This is the proper way of generating your dropdown list and preserve performance as you interact with the DOM only once thanks to the documentFragment
// These were not provided by OP but added to actually get this snippet running
var noOfPages = 5;
var start = 1;
var end = noOfPages;
var options = document.createDocumentFragment();
for (var i = start; i <= end; i++) {
var option = document.createElement('option');
option.value = i;
option.textContent = i;
options.appendChild(option);
}
document.getElementById("dropDown").appendChild(options);
<select id="dropDown" onchange="display(this.value)"></select>
I omitted the display function which is irrelevant as it refers to unprovided code.
I used arrays of strings to populate drop downs. How do I set the value of each drop down option to the same as the text content?
el.value = opt; doesn't appear to work.
var validCoursesKeys = ['opt 1','opt 2','opt 3','opt 4']
var validKeys = document.getElementsByClassName("validKeys");
setFields("courses");
function setFields(browser) {
//document.getElementById("result").value = browser;
var menuCounter = 1;
if (browser == "courses") {
for (var i = 0; i < validCoursesKeys.length; i++) {
var opt = validCoursesKeys[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
for (var j = 0; j < validKeys.length; j++) {
var elementClone = el.cloneNode(true);
elementClone.id = menuCounter;
menuCounter++;
validKeys[j].appendChild(elementClone);
}
}
} else if (browser == "rooms") {
var menuCounter = 1;
for (var i = 0; i < validRoomsKeys.length; i++) {
var opt = validRoomsKeys[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
for (var j = 0; j < validKeys.length; j++) {
var elementClone = el.cloneNode(true);
elementClone.id = menuCounter;
menuCounter++;
validKeys[j].appendChild(elementClone);
}
}
}
};
<select class="validKeys"></select>
<select class="validKeys"></select>
<select class="validKeys"></select>
You can achieve this using jquery. See below updated code using jquery
var validKeys = document.getElementsByClassName("validKeys");
function setFields(browser) {
//document.getElementById("result").value = browser;
var menuCounter = 1;
if (browser == "courses") {
$.each(validCoursesKeys , function(index, keys) {
var content='<option value="' + keys + '">' + keys + '</option>';
validKeys.append(content);
});
} else if (browser == "rooms") {
var menuCounter = 1;
$.each(validRoomsKeys , function(index, keys) {
var content='<option value="' + keys + '">' + keys + '</option>';
validKeys.append(content);
});
}
};
I have found several links to populate a dropdown list with an array but none of them work for me. Some links I have tried include:
This similar Stack Overflow question:
JavaScript - populate drop down list with array
This similar situation:
Javascript:
var cuisines = ["Chinese","Indian"];
var sel = document.getElementById('CuisineList');
for(var i = 0; i < cuisines.length; i++) {
var opt = document.createElement('option');
opt.innerHTML = cuisines[i];
opt.value = cuisines[i];
sel.appendChild(opt);
}
and the HTML:
<select id="CuisineList"></select>
But nothing is working. My goal is to populate a dropdown list from an external javascript array with values 0 to 255 so they can be used to come up with an RGB scheme. This is similar to the question that has been linked, but the linked question does not work when I copy and paste it into my text editor and preview it in Chrome.
try this:
i think your dom not ready when script executed
function ready() {
var cuisines = ["Chinese","Indian"];
var sel = document.getElementById('CuisineList');
for(var i = 0; i < cuisines.length; i++) {
var opt = document.createElement('option');
opt.innerHTML = cuisines[i];
opt.value = cuisines[i];
sel.appendChild(opt);
}
}
document.addEventListener("DOMContentLoaded", ready);
<select id="CuisineList"></select>
try this
var cuisines = ["Chinese","Indian"];
var innerData = '';
for(var i = 0; i < cuisines.length; i++) {
innerData += '<option value="' + 'cuisines[i]' + '">' + 'cuisines[i]' + '</option>';
}
document.getElementById('CuisineList').innerHTML = innerData;
When I trird to run the js code, it always said "Uncaught TypeError: Cannot read property '_id' of undefined" for
deployedID.push(data[j]._id);
So after some thinking, I believe the problem lies in
var j = deploy[i];
Is there any way to solve it? Thanks in advance.
Below is the complete code:
var deploy = [];
var deployedID = [];
var deployedename = [];
var deployedoname = [];
var deployedrank = [];
function popularizeTable(){
$.get("/SSS/getlist", function(data){
deploy = randomunique(data.length ,100);
for (var i = 0; i < 100; i++){
var j = deploy[i];
deployedID.push(data[j]._id);
deployedename.push(data[j].ename);
deployedoname.push(data[j].oname);
deployedrank.push(data[j].rank);
}
var str = " ";
var k = 0;
for (var i = 0; i < 5; i++){
str += "<tr>";
for(var j = 0; j < 20; j++){
str += "<td><section id=\"" + deployedID[k] + "\" class=\"container\"><div class=\"card\">"
str += "<figure class=\"front\"><img src=\"images/back.jpg\"></figure>";
str += "<figure class=\"back\"><img src=\"images/Clear/" + deployedename[k] + "/001.jpg\"></figure></div></td></section>";
k++;
}
str += "</tr>";
}
$("#table").append(str);
});
}
$( document ).ready(function() {
popularizeTable();
$(document).on("mouseover", ".card", function(){
$(this).toggleClass("flipped")});
});
function randomunique(max, num){
var uniquelist = [];
for (var j = uniquelist.length; j < num; j++){
var i = parseInt(Math.random() * (max - 1) + 1);
if (uniquelist.indexOf(i) == -1){
uniquelist.push(i);
}
}
return uniquelist;
}