creating huge optionlist with javascript vs delivering them in markup - javascript

I have a .net page that contains a huge amount of always the same dropdownlist in a repeater. The rendering performance of this site is...dispappointing.
I played around with delivering only the values and display texts for the dropdownlist to the page and then filling the selects with javascript. Works well, but I can't really see an improvement. In the end the page spends a lot of time with appending the options to the select tags.
Can someone with more experience tell me if it is theoretically possible to be faster than just filling the select tags in markup. Feels to me as if the browser has to "create" it at least once per select tag anyway, so it may not matter where the options come from. But maybe my javascript solution is just not very performat
Load time isnt't really a concern - it is for an intranet page.

here is what I did in the end:
I create an option list of 1 element for every select control to preserve the preselected values. If a select is focused or hovered over, I check if it contains onyl one element. If yes, I fill it dynamically from a collection of key values. It works without delay even for very large option lists.
I register an event listener for every select box and call this function
function fillDDL(ddl, arr) {
var i, len;
var optVals;
if (ddl.options.length === 1) {
var val = ddl.options[ddl.selectedIndex].value;
var docfrag = document.createDocumentFragment();
var opt;
ddl.remove(0);
opt = new Option("", "", true, false);
docfrag.appendChild(opt);
for (i = 0, len = arr.length; i < len; i++) {
optVals = arr[i];
opt = new Option(optVals[1], optVals[0], false, optVals[0] === val);
docfrag.appendChild(opt);
}
ddl.appendChild(docfrag);
}
Maybe innerHTML would be even faster, but right now I get instant results anyway.

Related

Issues with manipulating a drop down in Javascript

I'm currently using vanilla JS to match a given string, and then populate a drop down based on the match. I want to be able to click the drop down once to populate the drop down, but I currently have to click twice to then select the option, which would then add the same entries again (which isn't so much of an issue as once an option was selected, I can always reset the length to 0 so the user would likely not notice). I was thinking perhaps I need two event listeners instead of one but unsure of what direction to go or perhaps a "clickdown" and "clickup" event (if they even exist for mouse clicks?).
I'm still very much a beginner and not sure if what I am wanting to achieve is possible in one click or perhaps my approach is incorrect, so any pointers would be great.
document.getElementById('form').addEventListener('click', function() {
function addType(mactype) {
var type = document.getElementById('mode');
var option = document.createElement('option');
option.text = mactype;
type.add(option);
}
var macinput = MACinput.value;
var macoutput = MACoutput.value;
if (macinput.length > 0) {
var pattern = new RegExp("....-....-....");
if (pattern.test(macinput) == true) {
addType("Huawei -> Colon");
addType("Huawei -> HP");
addType("Huawei -> String");
}
}

Error adding options to a select menu with javascript

I was having two problems: the first is that javascript is not adding options to a menu, and the second was an "Unexpected or invalid token" error at the end of my for loop.
Update:
The token error was a weird character thing. I deleted the line that was causing the problem and retyped it and now I am not getting the error anymore, but my script still is not adding options.
I have read about adding options to a select menu but the answers I've found there haven't worked for me. I should point out that this is part of a Joomla website (v3.8), because that can cause some unexpected behaviour.
I have a function which is supposed to pick out a particular select menu based on the string "id", clear its contents, and re-populate it with the elements of the "options" array.
function resetSelectMenu(id, options){
// Selects the correct menu, enables it, and removes all of its options.
var selectMenu = jQuery('#sel-' + id);
selectMenu.prop('disabled', false);
selectMenu.empty();
// Makes an option element and sets its text and value.
var el = document.createElement("option");
el.text = 'blah';
el.value = 'blah';
// Does not succeed in adding an option to menu.
selectMenu.add(el);
// I declared loop variables here to make sure there are no re-declaration issues.
var i;
var opt;
// The loop is entered and the array is iterated through.
for(i = 0; i < options.length; i++){
opt = options[i];
el = document.createElement("option");
el.text = opt;
el.value = i + 1;
// Does not succeed in adding an option to menu.
selectMenu.add(el);
}​
}
The function does target the correct menu and clear its contents, but it is not adding the "blah" option or anything from the "options" array. I've tried using "appendChild(el)" instead of add but I get an error of the form "appendChild() is not a function". I did a lot of console logs to determine that all the parts of the code are working as expected except for "selectMenu.add(el);"
So this was just a noob mistake. I looked a bit harder and found this related question, and the top answer by Matt told me I needed to use append(el) instead of add(el). I looked into the documentation and the add method just affects the jQuery object but doesn't actually affect the DOM at all, whereas append does. If I were to use add I would need to explicitly tell the jQuery object to refresh the DOM.
It's also possible that there is still an issue with me using selectMenu.empty() instead of something like selectMenu.find('option').remove(), but at the moment it's not causing any errors. Since my select element only contains option elements I feel like these two commands would be the same, but on the other hand maybe the latter is better because it allows for the addition of different kinds of elements later.

Preventing DOMSubtreeModified event in Chrome from firing with every change in JS

everyone. There's an issue with Chrome (I don't know if it happens with other browsers as well). The situation is with a website that is a few years old. Was developped with standard JavaScript, not jQuery. There are thousands of codelines, so updating it now is not an option.
The thing is, this reads data from a database at the server, which returns some times 10 rows, some times over 500. That is the normal operation. In any case, the request is done via simple AJAX, and it returns an XML. The database responds in less than a second, the formatting of the XML is also in a second, maybe two on a slow day. But when JavaScript receives it back, that's the problem. With 10 elements in the XML there's no problem, but when it's 500, I want to kill myself.
After days of debugging and trying to find the problem, I finally did, but don't know how to fix it. The problem is that when the XML returns, every element is displayed in a simple <table>, meaning every node is basically a <tr> and every node's child is a <td> and <input type="text">. In the end, no matter how many rows it has, the table has 7 columns.
So here's an example of what it does. It simply goes through the nodes and creates the rows and cells with their input fields:
var table = document.getElementById("theTable");
for (var i = 0; i < theXML.childNodes.length; i++)
{
var row = table.insertRow(table.rows.length);
row.style.backgroundColor = "Red";
for (var j = 0; j < theXML.childNodes[i].childNodes.length; j++)
{
var cell = row.insertCell(row.cells.length);
cell.width = "200px";
cell.className = "cellClass";
var d = document.createElement("input")
d.type = "text";
d.width = "190px";
cell.appendChild(d);
}
}
Now, the problem
The code does what it's supposed to do, the table is created with the right rows, columns and inputs, but each and every single time it goes through a width, appendChild, className or other attribute setting, Chrome calls a DOMSubtreeModified event, which is first defined in the Startup() function in the content.js file (not part of my project, so it most be Chrome's). The event calls a onDomChange function which receives document as parameter, which only calls updateDocumentListeners and sends it the parameter, which calls updateInputListeners, which goes through EVERY SINGLE INPUT in the document using a for(), just to call updateInputListeners, which only return true or false depending on some conditions.
Now, when there are only 10 rows, that means that in the end we'll have 70 inputs, which in turn means that by the end it would have called the onDomChange several times, that is: 70 + 69 + 68 + ...., because it goes through everything that's been added before. And that was to be also multiplied by every single attribute you set.
In other words, with every input created, it calls onDomChange. On every attribute I set, it calls onDomChange. If I add a second input, it goes twice, once for the element and/or the attribute I'm setting and another for the previous one. Here's what it does:
//This is the code I found while debugging
function updateDocumentListeners(document)
{
var inputs = document.getElementsByTagName('INPUT');
for (var i = 0; i < inputs.length; ++i)
updateInputListeners(inputs[i]);
}
With 500 inputs, meaning also 500 cells, it simply won't end. Oh, and if there are already other inputs (including types hidden, radio, etc), they are included in the cycle. And then Chrome has the audacity to send a message with an option telling me that it's taking too long and prompts for whether I want to wait or cancel.
What I've tried
Since it all happens because of the event, I've tried to remove it, process the table and then reinstate it, but I can't remove it, because it's declared like this in content.js
document.addEventListener('DOMSubtreeModified', function(){ onDomChangeNoThrow(document); }, true);
This means I can't use removeEventListener, because it is defined as an anonymous function. I've already tried it.
Any suggestions?
Thanks.

Javascript clear content of selectbox

As part of my populating selectbox function I am clearing the contents of the populated select box and then inserting options to a empty box. Although the select box is not being cleared correctly and a lot of options are not removed. I am using the following code to clear the contents of the select box:
for(var i = 0; i < document.getElementById(selectbox).options.length; i++)
document.getElementById(selectbox).options[i] = null;
Why not all the options are removed from the selectbox?
You can simply do
document.getElementById(selectbox).options.length = 0;
You could also have removed the elements one by one, almost like you did, but you must take into account the fact the length of options changes when you iterate. The correct way to remove while iterating would have been
for (var i=document.getElementById(selectbox).options.length; i-->0;)
document.getElementById(selectbox).options[i] = null;
But the first solution is simpler of course.
var selectbox = document.getElementById(selectbox);
document.getElementById("emptyBox").innerHTML = selectbox.innerHTML;
selectbox.innerHTML = "";
As an alternative and more terse method of clearing all options of a select list, we can take advantage of JavaScript's falsey value of zero and then simply remove the option from the Dom:
function clearSelectList(list) {
// when length is 0, the evaluation will return false.
while (list.options.length) {
// continue to remove the first option until no options remain.
list.remove(0);
}
}
Usage would then be:
var list = document.getElementById("selectbox");
clearSelectList(list);
Or more succinctly:
clearSelectList(document.getElementById("selectbox"));
this example with new generation JavaScript. I do recommend to use.
[...cbrCenterSelectbox.options].forEach(option => option.remove())

How to re-create the Facebook "inline popup" inside of text while typing, using jQuery?

While typing into a textarea, I'd like certain character combinations to trigger an inline, popup "select box", just like in Facebook when you tag your friends in posts/comments.
For example, if the user were to type [friend:m they'd get a popup, with a list of their friends that start with m. As they continued typing, they'd get more narrow results... just like auto-complete.
I'd like to have other triggers too... [place: or [info: , etc...
I've been able to get up to where I can detect the triggers, but not experienced enough with Js/jQuery to finish this off. ;(
Here's what I've got:
var totalcount=0;
$('#Data').keyup(function (){
var arr = $(this).val().split(" ");
var matchitems = count('[place:', arr);
if(matchitems > totalcount) {
$('#Data').val($('#Data').val()+'foobar');
totalcount = matchitems;
}
if(matchitems < totalcount) {
totalcount = matchitems;
}
});
function count(value, array) {
var j=0;
for(var i=0; i < array.length; i++) {
if(array[i] == "[place:") {
j++;
}
}
return j;
}
This works, when I type [place: it appends "foobar" to textarea. Now I'm trying to take it further; to read the trigger, and then do a JSON call to create the popup list. How do I go about doing this? Know of any tutorials out there that cover this? Thanks!
Here's an example of the behavior you're looking for
example jsfiddle
I've actually done something similar, I modified it to fit what you're trying to do.
It looks for a matching [type: where type is friend, place, info etc
Loads the results
Handles up/down keys to toggle between results, enter to select (or mouse click), esc hides the auto complete results
Sets the input value based on selection made from auto complete

Categories