Improving jquery select speed - javascript

I have this code which manipulates the asp.net treeview html code.
This code gets run frequently, so its important that it runs as fast as possible.
I want to learn more about jquery selectors and improving its speed. So far I was able to get this code myself.
Some things I am not sure about is if you want the third child element, do I use [2] or .eq(2) or :nth-child(2)? Also what if I use $ to select something that was from an array of selected stuff, is this necessary, or is it already selected?
Does anyone know any tricks or hints I can do to improve my jquery select efficiency?
Thanks.
function showResultsOnTreeview(treeviewID, filenameDictionary) {
var sectionNodes = $("#" + treeviewID + " > table");
var numOfSections = sectionNodes.length;
var i, j, sectionName, divContainer, itemNodes, numOfItems, itemName, itemTag, itemPath;
for (i = 0; i < numOfSections; i += 1) {
sectionName = $(sectionNodes[i]).text();
divContainer = $(sectionNodes[i]).next('div');
divContainer.hide();
itemNodes = $('table', divContainer);
numOfItems = itemNodes.length;
for (j = 0; j < numOfItems; j += 1) {
itemTag = $('td', $(itemNodes[j])).eq(2);
itemTag.removeClass('treeViewResult');
itemName = getNameFromItem($(itemNodes[j]).text());
itemPath = filenameDictionary[itemName];
if (itemPath != null) {
if (itemPath.indexOf(sectionName + "/" + itemName) != -1) {
itemTag.addClass('treeViewResult');
divContainer.show();
}
}
}
}
}

There is some optimisation you can do. The first on is for sure to use .eq() instead of []. Like here, you hare creating a jQuery object :
var sectionNodes = $("#" + treeviewID + " > table");
But then later, you do this :
sectionName = $(sectionNodes[i]).text();
divContainer = $(sectionNodes[i]).next('div');
Here you are creating 2 more, unneeded, jquery object, you could just do this :
sectionName = sectionNodes.eq(i).text();
divContainer = sectionName.next('div');
Then, i do't know if you have a different way to do it, but if you can remove the "loop in a loop", that would be great.
After, instead of using context selectore ($('selector', $element)), use find. Context use find so it will reduce the number of function calls. Take this line for example :
$('td', $(itemNodes[j])).eq(2)
You are creating 2 jQuery object when you can do the same without an extra object and could use .find():
itemTag = itemNodes.eq(j).find('td').eq(2);
Basicly, use .find() instead of context and avoid creating unneeded jQuery object. Hope that will help.

Related

Update multiple table rows in javascript

Im currently quite new to javascript and im just trying to learn some basic things. Im not so bad in other languages so i do understand concepts etc.
I have a table with 10 rows for example, One of the cells is a "CaseID" and it exists for every row. Im trying to use the Math.Random property to generate random numbers.
My problem i hit first was i was using the ID property in my HTML and obviously this is unique, next i used class. I tried to append the output with an index but this again only worked for the first cell and nothing for the rest.
HTML:
<td class="caseID"></td>
JS:
var caseID = Math.floor((Math.random() * 10000));
document.getElementsByClassName("caseID")[0].innerHTML = caseID;
This all works great for the first cell/row but every other row returns blank. Im assuming because i need to perhaps create an array/indexing but im unsure on how to do this.
Could i create a variable:
var tds = document.getelementsbyclassname("caseID");
And maybe write a foreach etc? again not sure on how to do this.
Thanks in advance!
You can try a foreach like this, which would be a lighter syntax
document.getElementsByClassName("caseID").forEach(function(element) {
var caseID = Math.floor((Math.random() * 10000));
element.innerHTML = caseID;
})
You can use a good old for loop, use a more "separate the steps" way which could help you understand more how javascript works. I will use querySelectorAll but you can do it with getElementsByClassName
var myTds = document.querySelectorAll('caseID');
// You don't want to calculate the length at each loop
for (var i = 0, length = myTds.length; i < length; i++) {
var caseID = Math.floor((Math.random() * 10000));
var element = myTds[i];
element.innerHTML = caseID;
}
Hope it helps
How about this:
var tds = document.getElementsByClassName("caseID");
if ( tds.length ) { // just a check to make sure you've found somethiung
var caseID = Math.floor((Math.random() * 10000));
for(i = 0; i < tds.length; i++) {
tds[i].innerHTML = caseID;
caseID = Math.floor((Math.random() * 10000));
}
}
You can do this by write a foreach for class element in javascript.
var cases_list = document.querySelectorAll('.caseID');
Array.prototype.forEach.call(cases_list, function(elements, index) {
// conditional here.. access elements
});
OR if you use jquery than you can do this by
$('.caseID').each(function(index, obj){
//you can use this to access the current item
});

Object array gets overwritten by the last object

I have this array of objects being loaded:
$(document).ready(function () {
$("<div></div>").load("/Stats/Contents #stats", function () {
statcount = $(".list-group-item", this).length;
for (var j = 0; j < statcount; j++) {
statList.push(stat);
}
for (var i = 0; i < statcount; i++) {
statList[i].statId = document.getElementById("statId-" + (i + 1) + "").value;
statList[i].productDescription = document.getElementById("productType-" + (i + 1) + "").value;
statList[i].lastMeasuredInventoryAmount = document.getElementById("statLastMeasureAmount-" + (i + 1) + "").value;
}
)}
)}
.... and so on
Then I get the changed values and save them, however, in the ajax post call, all of the array objects are same (the last one assigned), looks like they get overwritten.
Any ideas? I saw these deferred/promise type code but not sure if there's simpler way.
Thanks.
It sounds like you take the statList array and then push that up to the server, with any respective change. Rather than building and maintaining a list like this, have you thought of switching it around and just grabbing the results out of the markup and building up the array at save point?
$("btnSave").on("click", function(e) {
var data = [];
$(".list-group-item").each(function() {
data.push({
statId: $(this).find(".statid").val(),
.
.
})
});
You wouldn't need to give every element an ID (but could) as my sample uses CSS classes to find the element within the current list item. Additionally, if these are inputs, you could serialize them from the root element more efficiently...

How to merge duplicate values in a for loop javascript

I am new to js and I don't understand much of codes and conditions in js.
My question is simple but I need someone to give me a good example if possible as I know what I need but it is getting hard to implement that in code.
This is my code with 2 arrays where the data is coming from.
blind_tmp = '';
for (i=0; i<#All of Blind Relationship Link.length; i++){
blind_tmp = blind_tmp + '<p>[**' + #All of Element Title[i] + '**](' + #All of Blind Relationship Link[i] + ')'
};
What simple needed is that. I want merge records that are duplicates printed.
for example: if Blind Relationship link is AF44 and after 6 elements this AF44 comes again so I want both to be written like 1.AF44,2.AF44
while now it is writing the elements how they come along
example:
AF11,AF22,AF33,AF44,AF55,AF66,AF77,AF44
so in this example you see two AF44
I want them to be written like this
AF11,AF22,AF33,AF44AF44,AF55,AF66,AF77
any help with a code example is appreciated.
The idea is to iterate through each element in the blindRelationshipLink and store those elements in a temporary array which will be used to check the number of occurrence of an array element.
var blindRelationshipLink = ['AF11','AF22','AF33','AF11','AF44','AF44','AF55','AF66','AF77','AF11','AF22','AF11'];
var arrTemp = [];
var p = '';
blindRelationshipLink.forEach(function(arr){
var count = 0;
arrTemp.forEach(function(a){
if(arr === a)
count++;
});
arrTemp.push(arr);
if(count){
count++;
arr= arr + '.' + count;
}
p = p + arr + ',';
});
alert(p);
You test by running the code snippet.
This approach is not best but it may serve your purpose.
Here is a snippet
var elemArray = ['AF11', 'AF22', 'AF33', 'AF44', 'AF55', 'AF66', 'AF77', 'AF44']; // Array of elements
//A new array which which will contain elements which pass our case
var finalArray = [];
elemArray.forEach(function(item) { // loop through main array
// Check if element is present or else push the element
if (finalArray.indexOf(item) == -1) {
finalArray.push(item);
} else {
// if element is there find the index
var getIndex = finalArray.indexOf(item);
// remove the element, else there will be duplicate
finalArray.splice(getIndex, 1);
//concate the matched element
var newElem = item + item;
// push the element in specfic index
finalArray[getIndex] = newElem;
}
})
console.log(finalArray)
Current drawback with this code is what will happen if there are multiple repeated item in the main array. For example presence of AF33 more than twice.
DEMO

How to get the next element of an array with Jquery onclick

Hi all i am trying to change the html of an object from an array of htmls. But i am having problem iterating properly. I managed to make it work once
EDIT
After a few complains about the clarity of my question I will rephrase it. I have a div panel called .trpanel and a button called #trigger2 (it is a next button). Then I have a series of divs with texts that contain translations. I want when I press the button (called next) to cycle through the translations one by one on the trpanel.
var ltranslation = [];
ltranslation[0] = $("#translation-en-1").html();
ltranslation[1] = $("#translation-ur-en").html();
ltranslation[2] = $("#translation-fr-en").html();
ltranslation[3] = $("#translation-it-en").html();
ltranslation[4] = $("#translation-sp-en").html();
ltranslation[5] = $("#translation-po-en").html();
ltranslation[6] = $("#translation-fr-en").html();
ltranslation[7] = $("#translation-de-en").html();
var l= ltranslation;
$("#trigger2").off('click').on('click',function(){
for (var i = 0; i <= ltranslation.length; i++){
if (i==7){i=0;}
$(".trpanel").html.ltranslation[i]; or ???//replace().ltranslation[]+i??? the code throws errors
}
});
I am quite new to Javascript and i am getting a bit confused with the types of objects and arrays and loops. I managed once to add the htmls but without replacing them ... so they all came one after the other. The i tried to change the code and it hasn't worked since. Any help will be greatly appreciated.
A lot of guessing, but seems like you are trying to do this :
var trans = $('[id^="translation-"]'),
idx = 0;
$("#trigger2").on('click',function(){
$(".trpanel").html( trans.eq(idx).html() );
idx = idx > 6 ? 0 : idx+1;
});
FIDDLE
I think you are trying to do this:
if (i == 7) {
i = 0; // I don't really know why you are doing this, but it will reset the loop
}
$(".trpanel").html(ltranslation[i]); //I'm passing ltranslation[i] to the html method. Instead of .html.ltranslation[i].
}
Also, without seeing any html, I'm not sure but I think you may want to iterate over .trpanel ?
Something like:
$(".trpanel").eq(i).html(ltranslation[i]);
Another thing (so you can make your code clearer I think). You can abstract the array population in a function, like this:
var ltranslation = [];
var languages = ["en-1", "ur-en", "fr-en", "it-en", "sp-en", "po-en", "fr-en", "de-en"];
$.each(languages, function(index) {
ltranslation[index] = $("#translation-" + this).html();
});
// Then you can use ltranslation
If you want to flip through several translations I would implement it that way:
var translations=["hej","hello", "hallo","hoy"];
var showTranslation=function(){
var current=0;
var len=translations.length;
return function(){
var direction=1;
if (current>=len) current=0;
$("#text").text(translations[current]);
current+=direction;
}
}();
$("#butt").on("click", showTranslation);
Fiddle: http://jsfiddle.net/Xr9fz/
Further: You should give your translations a class, so you could easily grab all of them with a single line:
$(".translation).each(function(index,value){ ltranslation.push(value); })
From the question : I managed once to add the htmls but without replacing them -
I think you want to add all of these items into $(".trpanel"). First, dont take the HTML of each element, clone the element itself :
//method ripped from Nico's answer.
var ltranslation = [];
var languages = ["en-1", "ur-en", "fr-en", "it-en", "sp-en", "po-en", "fr-en", "de-en"];
$.each(languages, function(index) {
ltranslation[index] = $("#translation-" + this).clone();
});
Then you could append everything into the container, so add the htmls but without replacing them. append takes in an array without replacing the previous html.
$("#trigger2").off('click').on('click',function() {
$(".trpanel").append(ltranslation);
});
I don't know what exactly you're tring to do, but I've put comments in your code to help you better understand what your code is doing. The net effect of your code is this (which I doubt you want) :
$("#trigger2").off('click').on('click',function(){
$(".trpanel").html(ltranslation[7]);
});
This is your code with some comments and minor changes
var ltranslation = [];
ltranslation[0] = $("#translation-en-1").html();
ltranslation[1] = $("#translation-ur-en").html();
ltranslation[2] = $("#translation-fr-en").html();
ltranslation[3] = $("#translation-it-en").html();
ltranslation[4] = $("#translation-sp-en").html();
ltranslation[5] = $("#translation-po-en").html();
ltranslation[6] = $("#translation-fr-en").html();
ltranslation[7] = $("#translation-de-en").html();
var l= ltranslation;
$("#trigger2").off('click').on('click',function(){
for (var i = 0; i < ltranslation.length; i++){
//if (i==7){i=0;} <-- This will cause an infinite loop won't it? are you trying to reset i? i will reset next time loop is called,
$(".trpanel").html(ltranslation[i]); //<-- this will overwrite elements with class .trpanel ltranslation.length times...
///you'll see only the value of translation[7] in the end
}
});
EDIT
To do what you want to do based on your comments, try this:
var ltranslation = [];
ltranslation[0] = $("#translation-en-1").html();
ltranslation[1] = $("#translation-ur-en").html();
ltranslation[2] = $("#translation-fr-en").html();
ltranslation[3] = $("#translation-it-en").html();
ltranslation[4] = $("#translation-sp-en").html();
ltranslation[5] = $("#translation-po-en").html();
ltranslation[6] = $("#translation-fr-en").html();
ltranslation[7] = $("#translation-de-en").html();
var counter = 0;//a global counter variable
$("#trigger2").click(function(){ //eeverytime button is clicked do this
$(".trpanel").html(ltranslation[counter]); //set the html to an element of array
counter++; //increment counter
if(counter==ltranslation.length) //reset the counter if its bigger than array len
counter=0;
});

How can I auto filter a HTML selectlist?

I have a HTML select list with quite a few (1000+) names. I have a javascript in place which will select the first matching name if someone starts typing. This matching looks at the start of the item:
var optionsLength = dropdownlist.options.length;
for (var n=0; n < optionsLength; n++)
{
var optionText = dropdownlist.options[n].text;
if (optionText.indexOf(dropdownlist.keypressBuffer,0) == 0)
{
dropdownlist.selectedIndex = n;
return false;
}
}
The customer would like to have a suggest or autofilter: typing part of a name should 'find' all names containing that part. I've seen a few Google Suggest like options, most using Ajax, but I'd like a pure javascript option, since the select list is already loaded anyway. Pointers anyone?
Change
if (optionText.indexOf(dropdownlist.keypressBuffer,0) == 0)
to
if (optionText.indexOf(dropdownlist.keypressBuffer) > 0)
To find dropdownlist.keypressBuffer anywhere in the optionText.
The YUI libraries have a library for this sort of functionality, called AutoComplete.
The DataSource for AutoComplete can be local javascript objects, or can be easily switched to Ajax if you change your mind.
The YUI components are pretty customizable with a fair bit of functionality.
Edit: I'm not sure if you can get it to work with a select box as required by the question though. Might be possible.
I would set up a cache to hold the options inside my select. And instead of filtering options in the select, I would clear the select, and re-populate it with matched options.
Pseudo-code galore:
onLoad:
set cache
onKeyPress:
clear select-element
find option-elements in cache
put found option-elements into select-element
Here's a little POC I wrote, doing filtering on selects from what is selected in another select--in effect chaining a bunch of selects together.
Perhaps it can give you a few ideas:
function selectFilter(_maps)
{
var map = {};
var i = _maps.length + 1; while (i -= 1)
{
map = _maps[i - 1];
(function (_selectOne, _selectTwo, _property)
{
var select = document.getElementById(_selectTwo);
var options = select.options;
var option = {};
var cache = [];
var output = [];
var i = options.length + 1; while (i -= 1)
{
option = options[i - 1];
cache.push({
text: option.text,
value: option.value,
property: option.getAttribute(_property)
});
}
document.getElementById(_selectOne).onchange = function ()
{
var selectedProperty = this
.options[this.selectedIndex]
.getAttribute(_property);
var cacheEntry = {};
var cacheEntryProperty = undefined;
output = [];
var i = cache.length + 1; while (i -= 1)
{
cacheEntry = cache[i - 1];
cacheEntryProperty = cacheEntry.property;
if (cacheEntryProperty === selectedProperty)
{
output.push("<option value=" + cacheEntry.value + " "
_property + "=" + cacheEntryProperty + ">" +
cacheEntry.text + "</option>");
}
}
select.innerHTML = output.join();
};
}(map.selectOne, map.selectTwo, map.property));
}
}
$(function ()
{
selectFilter([
{selectOne: "select1", selectTwo: "select2", property: "entityid"},
{selectOne: "select2", selectTwo: "select3", property: "value"}
]);
});
use this filter script
http://www.barelyfitz.com/projects/filterlist/

Categories