Jquery help needed- infinite loop? - javascript

i have a problem with this code:
var par = [];
$('a[name]').each(function() {
if (($(this).attr('name')).indexOf("searchword") == -1) {
par.push($(this).attr('name'));
$('.content').empty();
for (var i = 0; i < par.length; i++) {
$(".content").append('<a id="par" href="#' + par[i] + '">' + par[i] + '</a><br />');
}
}
});
It causes ie and firefox to popup the warning window "Stop running this script". But it happens only when there is a very very large amount of data on page. Any ideas how to fix it?

Your code should look like this:
var par = [];
$('a[name]').each(function() {
if (($(this).attr('name')).indexOf("searchword") == -1) {
par.push($(this).attr('name'));
}
});
$('.content').empty();
for (var i = 0; i < par.length; i++) {
$(".content").append('<a id="par" href="#' + par[i] + '">' + par[i] + '</a><br />');
}
There is no reason for the second loop to be inside the first - that will just cause a lot of unneeded work.
You can make this code a bit simpler by removing the par array and the second loop, and just creating the content inside the first loop:
$('.content').empty();
$('a[name]').each(function() {
var name = $(this).attr('name');
if (name.indexOf("searchword") == -1) {
$(".content").append('<a id="par" href="#' + name + '">' + name + '</a><br />');
}
});

Browsers run all javascript (and most page interaction) on a single thread. When you run a long loop like this with no interruptions, the UI is totally frozen. You should try to make your algorithm have to do less, but in case that's not possible you can use this trick where you do a bit of work, then pause and give the browser control of the UI thread for a bit, then do more work.
var $targets = $('a[name]');
var current = 0;
var i = 0;
function doSomeWork() {
if (i == $targets.length) return;
var $t = $targets[i];
if (($t.attr('name')).indexOf("searchword") == -1) {
par.push($t.attr('name'));
$('.content').empty();
for (var i = 0; i < par.length; i++) {
$(".content").append('<a id="par" href="#' + par[i] + '">' + par[i] + '</a><br />');
}
}
i++;
window.setTimeout(arguments.callee, 0);
}
This does one iteration of your loop in a function before yielding. It might be a good idea to do more than just one in a function call, but you can experiment with that. An article on this idea: http://www.julienlecomte.net/blog/2007/10/28/

Related

Issue when trying to use jQuery's window.open function in combination with a for-loop to iterate through an array

Let's say I have an array of links like this:
var playlist = [
"",
"https://www.youtube.com",
"https://www.google.com",
"https://www.facebook.com",
"https://www.instagram.com"
];
And a bunch of boxes generated in the following way:
for(var i = 1; i < 5; i++) {
$(".container").append("<div class='luke luke-" + i + "'>" + "<h3 class='nummer'>Luke " + i + "</h3> " + "</div>");
}
I then want to iterate through this array to open a specific link when a box is clicked.
for(var i = 1; i < 5; i++) {
$(".luke-" + i).click(function(){
window.open(playlist[i], "_blank");
})
}
That doesn't seem to work at all, however the example below does exactly what I want.
$(".luke-1").click(function(){
window.open(playlist[1], "_blank");
})
$(".luke-2").click(function(){
window.open(playlist[2], "_blank");
})
$(".luke-3").click(function(){
window.open(playlist[3], "_blank");
})
$(".luke-4").click(function(){
window.open(playlist[4], "_blank");
})
$(".luke-5").click(function(){
window.open(playlist[5], "_blank");
})
So this works, but it's a pain in the ass to setup as I want to have 25 boxes in total and this solution offers little to no flexibility if I want to increase or decrease that amount at a later time. What am I doing wrong with the for-loop that's causing issues here?
If I use
console.log(playlist[i]);
inside of the for-loop, it simply returns "undefined" regardless of what box I click in case that helps.
You can do this much easier and simpler using a data attribute.
HTML
<div class="container"></div>
Javascript/jQuery
var playlist = [
"",
"https://www.youtube.com",
"https://www.google.com",
"https://www.facebook.com",
"https://www.instagram.com"
];
for(var i = 1; i < 5; i++) {
$(".container").append("<div class='luke' data-url='" + playlist[i] + "'>" + "<h3 class='nummer'>Luke " + i + "</h3> " + "</div>");
}
$('.luke').click(function() {
window.open($(this).data('url'));
});
Demo Here
You are not doing right.
EXAMPLE FIDDLE
var playlist = [
"https://www.youtube.com",
"https://www.google.com",
"https://www.facebook.com",
"https://www.instagram.com"
];
var container = $("#container");
for(var i = 1; i < 5; i++) {
container.append('<div class="luke" db-id="'+ i + '"><h3 class="nummer">Luke ' + i + '</h3></div>');
}
$(".luke").click(function(i){
window.open(playlist[$(this).attr('db-id')], "_blank");
});
for(var i = 1; i < 5; i++) {
$(".luke-" + i).click(function(i){
window.open(playlist[i], "_blank");
})
}
The click event will launch your function only inside the scope of the loop. This means that once the loop have finished, ( and counting from 0 to 5 is insanely fast for your computer ) there's no more function attached to your click event. In other terms, as long as i < 5, your click function will work as you expect, but after that, the click event will no longer call the function you created.
One solution could to be attach a function to the onclick attribute in the HTML like this :
for(var i = 1; i < 5; i++) {
$('<div/>', {
'class': 'luke luke-' + i,
'click': yourFunction(i)
}).appendTo(${'.container'});
$('<h3/>', {
'class':'nummer',
'html': 'Luke' + i
}).appendTo(${'.luke-'+i})
}
and then write a function like this :
function yourFunction(index){
window.open(playlist[index], "_blank");
}
Simple way by using Hyperlink
hyperlinks
Demo Here

Add javascript condition inside text variable

I have code working fine but I wanna simplify:
<script type="text/javascript">
function RenderPager(items) {
for (var i = 0; i < items.length; i++) {
var li = "<li";
if(i == 0){
li += " class='first'";
}
li +=">" + i + "</li>";
// do something else
}
}
</script>
I would like to have condition inline something like this:
for (var i = 0; i < items.length; i++) {
var li = "<li" + if(i == 0){ li += " class='first'" }; + ">" + i + "</li>";
// do something else
}
But this is not working and I tried everything but I don't know how to combine javascript condition in text variable. Is it possible?
You can use the conditional operator (?..:), also known as the ternary operator:
var li = "<li" + (i == 0 ? " class='first'" : "") + ">" + i + "</li>";
Also note, this could probably also be done using a little CSS with the :fist-child pseudo-class, but it's not supported by older versions of IE. See this compatibility chart:
li:first-child {
/* applies only to the first <li> element in a list */
}

jquery append() works in chrome debugger and on IE, but not in Chrome

I have a strange situation where my code works in the debugger (Chrome), and also work on IE 9, but doesn't work in chrome, and in Firefox. All I'm trying to do is to append a bunch of list elements to a list.
HTML:
<div id="FriendSelector">
<ul></ul>
</div>
JS:
var friends = []; //this gets loaded with about 600 friend objects (name, icon, id) earlier
function openFriendSelector() {
var $friendSelector = $('#FriendSelector');
$friendSelector.show();
bindFriends();
}
function bindFriends() {
var $list = $('#FriendSelector ul');
for (i = 0; i < friends.length; i++) {
var friend = '<li id="' + friends[i].id + '"><div><img src="' + friends[i].icon + '" class="avatar"/>' + friends[i].name+ '</div></li>';
$list.append(friend);
}
}
When I click the button that opens the FriendSelector DIV (initially hidden), I see a blank DIV, however, if I close the popup and re-open it, the friends are there...
Any help is appreciated.
Found the issue. The array was taking a few seconds to get loaded (via ajax). So, after the page loads, if I wait a couple seconds and then open the div, it works. Which explains why it worked in the debugger.
Try to avoid so many .append() calls at once, so replace your following code:
for (i = 0; i < friends.length; i++) {
var friend = '<li id="' + friends[i].id + '"><div><img src="' + friends[i].icon + '" class="avatar"/>' + friends[i].name+ '</div></li>';
$list.append(friend);
}
for this one:
for (i = 0, friend=''; i < friends.length; i++) {
friend +='<li id="' + friends[i].id + '"><div><img src="' + friends[i].icon + '" class="avatar"/>' + friends[i].name+ '</div></li>';
}
$list.append(friend);
UPDATE:
Try to load friends prior to showing the div, like this:
function openFriendSelector() {
bindFriends();
}
function bindFriends() {
var $list = $('#FriendSelector ul');
for (i = 0, friend = ''; i < friends.length; i++) {
friend = '<li id="' + friends[i].id + '"><div><img src="' + friends[i].icon + '" class="avatar"/>' + friends[i].name+ '</div></li>';
}
$list.append(friend);
$list.parent().show();
}

Get element by tag and class

I have a script
var firstImg = row.getElementsByTagName('img')[0];
and later
if (x){ firstImg.src='/images/checked.png'; }
I'd like to define that the img should be of class='something'
(Get first img with class='something')
Use the
querySelectorAll('img.classname')[0]
this returns first image with class set to class name. However jQuery is better!!
$('img.classname')
Just set it...
firstImg.className += "something";
...or...
firstImg.classList.add("something");
If you can get away with not supporting older browsers.
Further Reading (disclaimer: link to my own blog).
If you're intending to get elements with a certain class name, you can use...
document.getElementsByClassName("something");
...or...
document.querySelectorAll(".something");
Keep in mind getElementsByClassName() isn't in <= IE8.
You can use...
var getElementsByClassName(nodeList, className) {
var i, results = [];
for (i = 0; i < nodeList.length; i++) {
if ((" " + nodeList[i].className + " ").indexOf(" " + className + " ") > -1) {
results.push(nodeList[i]);
}
}
return results;
}
Of course, it's super simple if you're using jQuery...
$(".something");
this selects the first img with class='something':
var firstImg = $('img.something')[0];
If you could not throw away the old browsers, then you need a loop.
var imgs = row.getElementsByTagName('img'),
some_class = 'something',
i, first_img;
for (i = 0; i < imgs.length; i++) {
if ((' ' + imgs[i].className + ' ').indexOf(' ' + some_class + ' ') > -1) {
first_img = imgs[i];
break;
}
}

javascript code does not execute after a loop

I have the following code (snippet from a larger function):
var res = data.results;
for (var i=0;i<res.length;i++) {
$('<option value="' + res[i] + '">' + res[i] + '</option>').appendTo(sel);
}
if (data.select && data.select!='') { sel.val(data.select); }
For some reason, the
if (data.select && data.select!='') { sel.val(data.select); }
line just wasn't executing, and is appearing greyed out in Firebug suggesting that Firebug somehow knows it is not reachable. If I make a simple change to the code like this:
var res = data.results;
for (var i=0;i<res.length;i++) {
var opt = '<option value="' + res[i] + '">' + res[i] + '</option>';
$(opt).appendTo(sel);
}
if (data.select && data.select!='') { sel.val(data.select); }
the last line runs without issue.
I found similar post on here where the for loop had a <= for the while parameter causing an error and although this is not the case here, when I stepped through the code it was trying to execute the loop one more time than it should have, i.e. if res.length was 4, it was allowing i to increment to 4 and then trying to execute the code in the loop which was therefore ending the code because res[i] was out of range, even though it wasn't placing an error in the console. If I change the code as demonstrated, the loop does not run when i == res.length
So, how did Firebug know that the original code wasn't going to allow execution past the end of the loop, and why is the loop executing one more time than it should?
The entire function is below and is a success callback from a jQuery ajax call which populates a select with the values received from the server:
function GetDeptsOK(data, textStatus, jqXHR) {
var sel = $('#orgpicker').find('select[name="orgpicker-dept"]');
if (sel.length == 0) {
var cell = $('#orgpicker-deptcell');
cell.text('');
$('<select name="orgpicker-dept"></select>').appendTo(cell);
sel = $('#orgpicker').find('select[name="orgpicker-dept"]');
} else {
sel.find('option').remove();
}
$('<option value=""></option>').appendTo(sel);
var res = data.results;
for (var i=0;i<res.length;i++) {
$('<option value="' + res[i] + '">' + res[i] + '</option>').appendTo(sel);
}
if (data.select && data.select!='') { sel.val(data.select); }
}
replace this by
var res = data.results;
for (var i=0;i<res.length;i++) {
if(!res[i])
break;
var opt = '<option value="' + res[i] + '">' + res[i] + '</option>';
$(opt).appendTo(sel);
}
if (data.select && data.select!='') { sel.val(data.select); }

Categories