jQuery element somehow cached in setInterval - javascript

I'm trying to trigger a click on an element every x seconds. It's not the exact same element every time (depending on which tab a user has selected, it should click that tab), but they are all in the same container (with id #container. The selected element has the class .selected and gets that class when it has been clicked on by a user.
This is the code I have:
var feedContainer = $('#container');
window.setInterval(function () {
var selectedTab = feedContainer.find('.selected');
selectedTab.trigger('click');
}, 10000);
The problem is that between the timeouts, if a user clicks on another tab, this part doesn't pick up on that: var selectedTab = feedContainer.find('.selected');. It just gets the one that was selected before, not the new one that has the class. How do I avoid that?
It works fine if I do the entire selection in the timer each time (var selectedTab = $('#container .selected');). It seems to be somehow caching the results from the last run.
Why is this and how do I force it to fetch the correct element?

You are already caching the element yourself by doing this:
var feedContainer = $('#container');
If the contents change after you assign it to the variable then that variable won't get updated with the new contents automagically.
Just use it like this $('#container'); directly whenever you want to do operations on it.

What you're doing is that in the beginning, you gather some elements that match the selection (using $('#container')) but later on, you change the content of #container which is not reflected in the jQuery object in feedContainer. Simply get the container on each iteration.
window.setInterval(function () {
var feedContainer = $('#container');
var selectedTab = feedContainer.find('.selected');
selectedTab.trigger('click');
}, 10000);

window.setInterval(function () {
var selectedTab = $('#container').find('.selected');
selectedTab.trigger('click');
}, 10000);
As container is not changed above is proposed.

First of all, an ID should ideally be used to identify a "single" element, not multiple elements. Changing that would help you out by spreading the elements with the same name using a "class" identifier. Changing that might help you out a lot.

I'd do it like this. Short, to the point and no variable assigning thus no caching.
window.setInterval(function () {
$('#container .selected').trigger('click');
}, 10000);

Related

Javascript onclick event firing for id but not for class

I'm fairly new to Javascript, and am trying to get an 'on click enlarge' kind of effect, where clicking on the enlarged image reduces it again. The enlarging happens by replacing the thumbnail by the original image. I also want to get a slideshow using images from my database later on.
In order to do that, I made a test where I replace the id which indicates enlarging is possible by a class and I also use a global variable so that I can keep a track of the url I'm using. Not sure this is the best practice but I haven't found a better solution.
The first part works fine, my image gets changed no problem, values are also updated according to the 'alert' statement. However, the second part, the one with the class never triggers.
What am I doing wrong (apart from the very likely numerous bad practices) ?
If instead of changing the class I change the id directly (replacing .image_enlarged by #image_enlarged, etc.), it seems to call the first function, the one with the id, yet outputs the updated id, which is rather confusing.
var old_url = "";
$(function(){
$('#imageid').on('click', function ()
{
if($(this).attr('class')!='image_enlarged'){
old_url = $(this).attr('src');
var new_url = removeURLPart($(this).attr('src'));
$(this).attr('src',new_url); //image does enlarge
$(this).attr('class',"image_enlarged");
$(this).attr('id',"");
alert($(this).attr('class')); //returns updated class
}
});
$('.image_enlarged').on('click', function (){
alert(1); //never triggered
$(this).attr('src',old_url);
$(this).attr('class',"");
$(this).attr('id',"imageid");
});
});
function removeURLPart(e){
var tmp = e;
var tmp1 = tmp.replace('thumbnails/thumbnails_small/','');
var tmp2 = tmp1.replace('thumbnails/thumbnails_medium/','');
var tmp3 = tmp2.replace('thumbnails/thumbnails_large/','');
return tmp3;
}
As for the html, it's really simple :
<figure>
<img src = "http://localhost/Project/test/thumbnails/thumbnails_small/image.jpg" id="imageid" />
<figcaption>Test + Price thing</figcaption>
</figure>
<script>
document.write('<script src="js/jquery-1.11.1.min.js"><\/script>');
</script>
<script type="text/javascript" src="http://localhost/Project/js/onclickenlarge.js"></script>
From the API: http://api.jquery.com/on/
The .on() method attaches event handlers to the currently selected
set of elements in the jQuery object.
When you do $('.image_enlarged').on(...) there is no element with that class. Therefore, the function is not registered in any element.
If you want to do so, then you have to register the event after changing the class.
Here's an example based on your code: http://jsfiddle.net/8401mLf4/
But this registers the event multiple times (every time you click) and it would be wrong. So I would do something like:
$('#imageid').on('click', function () {
if (!$(this).hasClass('image_enlarged')) {
/* enlarge */
} else {
/* restore */
}
}
JSfiddle: http://jsfiddle.net/8401mLf4/2/
Try using:
addClass('image-enlarged')
instead of:
.attr('class',"image_enlarged");
the best way to do this would be to have a small-image class and a large image class that would contain the desired css for both and then use addClass() and removeClass depending on which you wanted to show.

Binding setTimeOut to some function with specific element

I am trying to do a notification pop up, each pop up is dynamically generated after ajax fetched the data.
The pop up each will have a time limit of 10 seconds before it fade out. Something like you see on Facebook's notifications on the left bottom corner.
Each pop up will be hidden according to the time it is added and the timelimit.
Here's an example of my code:
function hidePop(obj){
$(obj).hide();
}
function newpopup(data){
$('#notifications').prepend('<li class="new" style="display:none;">'+data+'</li>');
$('.new').fadeIn(200, function(){
var $this = $(this);
$(this).removeClass('new');
setTimeout(function(){
hidePop($this)
}, 10000);
});
}
As you can see above, my AJAX call will call for newpopup with the data. Once it fades in completely the setTimeout function will run.
This works, however, after a few more li is appended, those new lis will keep hiding itself once its showed.
Note: I remove class new once everything is done since new will then be used for the latest incoming popups.
I think the setTimeOut is either not stopped or targeting all of the lis.
Is my method a problem or is there any better solutions?
Instead of simply prepending an <li> tag as a string that states a class, then selecting the class with jQuery, I would suggest using the DOM to create the <li> element and hold a reference to it like so:
function hidePop(obj){
obj.hide(); //obj parameter already wrapped by jquery, no need to do it again
}
function newpopup(data){
var newLi = $(document.createElement("li")); //createElement then wrap jQuery around it
newLi.html(data).css("display", "none"); //jQuery set innerHTML and CSS
$('#notifications').prepend(newLi); //Prepend to list
newLi.fadeIn(200, function() { //Select this and only this li element
setTimeout(function(){
hidePop(newLi); //Closure; reference to the same "this and only this li"
}, 10000); //10s
});
}
In the body of the anonymous function in setTimeout, $this is overwritten. Try this:
function newpopup(data){
$('#notifications').prepend('<li class="new" style="display:none;">'+data+'</li>');
$('.new').fadeIn(200, function(){
var $this = $(this);
$(this).removeClass('new');
var thatPopup = $this;
setTimeout(function(){
hidePop(thatPopup)
}, 5000);
});
}

isotope append method removes current elements

I am attempting to append elements to a list using the .load() method to retrieve elements from another page.
But when I use this method it is removing the current DOM elements and replacing them, rather than appending them to the list.
Any help would be much appreciated.
Code below:
var $container = $('#container');
$('#insert a').click(function () {
var newEls;
$container.load('../pages/2.html .element', function () {
newEls = $(this);
});
$container.isotope('insert', $(newEls));
return false;
});
Surely you should be telling isotope to insert after they have been loaded.
e.g.
$container.load('../pages/2.html .element', function () {
newEls = $(this);
$container.isotope('insert', $(newEls));
});
otherwise you are inserting the current contents (or an empty div) before loading them.
Your $container.isotope('insert', $(newEls)); is executing before the load even starts (the load is asynchronous so you can only trust something to run against the loaded data if it is in the callback/function).
In addition to this, you are reloading the entire contents of the '#container' so it simply erases the previous children. You need to append the content, e.g. by loading into a dummy element then appending to your container.
maybe something like this (untested):
var $container = $('#container');
$('#insert a').click(function () {
var $newEls;
$container.append('<div id="#loadme"></div>');
var $loadme = $('#loadme');
$('#loadme').load('../pages/2.html .element', function () {
$newEls = $loadme.children();
$loadme.children().unwrap();
$container.isotope('insert', $newEls);
});
return false;
});
Normally I would not use load in this situation, but an AJAX get call and append the returned elements. Much simpler.

is this an acceptable use of jquery data()?

I'm using jquery data() to attach the name of a div I'd like to show when another div (.panel_button) is clicked. I'm doing the attaching of this div's id to the button when the document is ready. Is this an okay way to do this? Or is it too resource intensive and unprofessional-looking?
$(document).ready(function(){
$('#sample_button').data('panel', 'sample_kit_container');
$('#mail_button').data('panel', 'mail_container');
$('#mbillboard_button').data('panel', 'mbillboard_container');
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
$('#' + panel).show();
});
});
Yeah, that should work just fine. As an alternate, you could store the actual element itself (assuming it already exists) rather than finding it each time:
$('#sample_button').data('panel', $('#sample_kit_container'));
$('#mail_button').data('panel', $('#mail_container'));
$('#mbillboard_button').data('panel', $('#mbillboard_container'));
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
panel.show();
});
Another option would be to store the actual jQuery element in the data property, so no need to do a second selection:
$(function(){
$('#sample_button').data('panel', $('#sample_kit_container'));
$('#mail_button').data('panel', $('#mail_container'));
$('#mbillboard_button').data('panel', $('#mbillboard_container'));
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
panel.show();
});
});
#thomas, in my opnion, your solution is actually better than those in the other answers.
Including the whole object inside the data attribute may not always work. For example, what if the $('#sample_kit_container') object doesn't exist on load, but rather ofter an ajax load.
...
Only one tiny comment! why don't you call the data object: panelId. It would be more a bit intuitive.

How to hide/close other elements when new element is being opened?

Ran into problem with creating custom select dropdown plugin in jQuery. I'm at the one-at-the-time-open feature. Meaning, that when you open a dropdown, then other(s) will close.
My first idea was to create some global array with all dropdowns in it as objects. Then in the "opening"-function, I would add the first line to first check that none of the dropdowns are open (if open, then close them.)
I created a very scaled version of my script: http://jsfiddle.net/ngGGy/1/
Idea would be to have only one dropdown open at the time. Meaning, that when you open one, other(s) must be closed, if not they will automatically close when a new one is opened.
Your dropdown set seems to behave like an accordion.
This is easier to accomplish if you wrap each dropdown in a div with a class, then use that to target all the dropdown uls you have.
I forked your jsfiddle with a working example.
(EDIT updated fiddle link)
You can keep track of the DropDownSelectized lists like this: http://jsfiddle.net/pimvdb/ngGGy/3/.
(function($){
var lists = $(); // cache of lists
$.fn.DropDownSelect = function (settings) {
jQuery.globalEval("var zindex = 100");
var thiselement = $(this);
var thislist = thiselement.next('ul');
lists = lists.add(thislist); // add current one to cache
thiselement.click(function () {
lists.slideUp(); // hide all lists initially
if (thislist.is(':visible')) {
thislist.slideUp();
} else {
thislist.css('z-index', ++zindex).slideDown();
}
});
};
})(jQuery);
You're definitely on the right track, but if you're only going to have one dropdown list open at a time then you want them to be related somehow. Fortunately your markup is already there, so all we should have to do is modify the JS. I've updated your jsFiddle project here: http://jsfiddle.net/ninjascript/ngGGy/4/
First the selector. jQuery will let you select attributes that are similar by using ^= like this:
$('div[id^=button]').DropDownSelect();
Now we just have to update your plugin a bit. Notice that what used to be 'thislist' is now called 'everylist'. Now we can enforce that every list closes on click before opening the list associated with the button that was clicked.
(function($){
$.fn.DropDownSelect = function (settings) {
jQuery.globalEval("var zindex = 100");
var thiselement = $(this);
var everylist = thiselement.next('ul');
thiselement.click(function () {
var thislist = $(this).next('ul');
if (everylist.is(':visible')) {
everylist.slideUp();
}
thislist.css('z-index', ++zindex).slideDown();
});
};
})(jQuery);
Good luck!
Why not raise an event that all drop-downs subscribe to. pass in the id (or instance) of the one currently being opened. In the handler check whether the handling instance is the one being opened. If not, close it.

Categories

Resources