I'm using the following jquery code in my page:
jQuery(window).load(function(){
jQuery('#narrow-by-list dd > ol.filter_list').each(function(){
var FormHeight = jQuery(this).outerHeight();
if(FormHeight > 70){
jQuery(this).next('.layer_nav_more').css("display", "inline-block");
jQuery(this).height(70).css("display", "block");
}else{
jQuery(this).height(70).css("display", "block");
}
});
jQuery(".layer_nav_more").click(function(){
jQuery(this).prev('.filter_list').animate({ height:205 }, 500, function() {
jQuery(this).addClass("scrollable");
});
});
});
The page also uses ajax calls to update it's content, so after content is refreshed the jquery code is ignored. I don;t think that posting the full js file which handles ajax will help you. I guess that the following lines should be quite ok for you to understand what's going on:
requestUrl = document.location.href
if (requestUrl.indexOf('#') >= 0) {
var requestUrl = requestUrl.substring(0,requestUrl.indexOf('#'));
}
if (requestUrl.indexOf('?') >= 0) {
requestUrl = requestUrl.replace('?', '?no_cache=true&');
} else {
requestUrl = requestUrl + '?no_cache=true';
}
requestUrl = this.replaceToolbarParams(requestUrl);
this.showLoading();
new Ajax.Request(requestUrl, {
method : 'post',
parameters : parameters,
onSuccess: this.onSuccessSend.bindAsEventListener(this),
onFailure: this.onFailureSend.bindAsEventListener(this)
});
What can I do to fix this?
EDIT:
I changed the code based on David's recommendations
jQuery(window).load(function(){
function adjust_list_height(){
jQuery('#narrow-by-list dd > ol.filter_list').each(function(){
var FormHeight = jQuery(this).outerHeight();
if(FormHeight > 70){
jQuery(this).next('.layer_nav_more').css("display", "inline-block");
jQuery(this).height(70).css("display", "block");
}else{
jQuery(this).height(70).css("display", "block");
}
});
}
adjust_list_height();
jQuery(document).on('click', '.layer_nav_more', function(){
jQuery(this).prev('.filter_list').animate({ height:205 }, 500, function() {
jQuery(this).addClass("scrollable");
});
});
});
so after content is refreshed the jquery code is ignored
No it isn't. It's not going to be automatically re-invoked, clearly, but why should it be? The handler you posted is for the window's load event. Unless you're loading the window again, I wouldn't expect the code to execute again.
It sounds like the problem is that you're adding new elements to the page after you've added click handlers to existing elements. Keep in mind that handlers are attached to elements, not to selectors. So if a particular element doesn't exist when you execute this code, it's not going to get a click handler.
The standard approach to this is to defer handling click events to parent elements. Any common parent element will do, as long as it's not removed/replaced during the life of the page. document is often used for this, but any parent div or anything like that would work just as well. Something like this:
jQuery(document).on('click', '.layer_nav_more', function(){
//...
});
What this does is attach the actual click handler to document instead of to the matching .layer_nav_more elements. When any element invokes a click, that event will propagate upwards through the parent elements and invoke any click handlers on them. When it gets to this handler on the document, jQuery will filter for the originating element using that second selector. So this will effectively handle any clicks from .layer_nav_more elements.
Any other functionality that you need to invoke when the page content changes (functionality besides delegate-able event handlers) would need to be re-invoked when you logically need to do so. For example, executing .each() over a series of elements like you're doing. There's no way to "defer" that, so you'd want to encapsulate it within a function of its own and simply execute that function whenever you need to re-invoke that logic.
Related
I hit a problem with the onclick function when i add divs with ids like "n_block"+(1-~). When I use the jquery zoom function on the objects to make them smaller or bigger onClick doesn't work anymore. I'm not really good at programming so the code might be kind of confusing.
Heres the code i use for the onClick of items:
$(document).on("click",function (e, ui){
//When the document gets clicked, check if one of the items was clicked.
if($(e.target).is($("#n_block" + cloneCount1)) || $(e.target).is($("#n_block" + cloneCount1+ " span"))){
//Set current item.
var item = $("#n_block" + cloneCount1);
//Set style to current item.
item.css("border-color", "Black");
item.css("border-width","2px");
item.css("background-color", "floralwhite");
jsPlumb.repaintEverything();
//Check if key Delete was pressed while item selected & delete that item with his children.
$('html').keydown(function(e){
if(item.css("border-width")=="2px"){
if(e.keyCode == 46) {
/* Prevents line bugging*/
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
var razred = getClass(item, "b_"),
id = item.prop("id");
item.remove();
if(razred == "b_2"){
$(".ovoj."+id).remove();
}
else if (razred == "b_4"){
$(".ovojLoop."+id).remove();
$(".empty_block_c."+id).remove();
}
if ( $('.objects').find('div').length == 2) {
$(".objects").empty();
$(".objects").append('<div class="b_s" id="start_block">START</div><p id="start_text">Insert symbols here!</p><div class="b_s" id="end_block">STOP</div> ');
}else{
/* Connects objects together with line. ****/
povezi(cloneCount, tip_crte, ".objects");
}
}
jsPlumb.repaintEverything();
}
});
}
// If item is not clicked set this css to the current item.
else{
$("#n_block" + cloneCount1).css("border-width","1px");
jsPlumb.repaintEverything();
}
});
And heres the zoom code for zooming in when button is clicked:
var currentZoom = 1.0;
$(".zoomin").click(function (){
//Detaches the connections from item to item.
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
//Prevents spamming of button, animates the objects
$(".project").stop().animate({ "zoom": currentZoom += .1}, "slow", function() {
if(!$(".objects").children().is($("p"))){
povezi(cloneCount, tip_crte, ".objects");
}
});
});
Use event delegation for binding events to dynamically added elements.
$(document).on('click', ".zoomin", function (){
//Your code.
});
When you use normal .click() to bind event to an element, then that even gets bound to only those elements which exist in the DOM at the moment of the execution of code. Using event delegation, you can tell jQuery that we need to add the handler to every '.zoomin' element which comes inside a particular element no matter when it is added.
The solution depends when exactly is the script which tries to bind the events are executed.
For Eg: Lets assume this script is in document ready function of jquery
$(document).ready(function(){
$(".zoomin").click(function (){
//your logic here
});
});
Here this script is executed when the page HTML is completed loading into the browser. Now when the script executes it tries to find a element with the class zoomin and if found it will add a event to that element and move on. If the element is not found the script just moves on. So we should actually take care of when the script is executed and is the intended element available at that particular instant of time. If the element is not yet available in the HTML (element might come in later dynamically using jquery) we have 2 options to bind event to the element.
1) Execute the script when the element is being added into the HTML: Lets say I have a event which brings up a pop up with some image. Now I want to zoomin and zoomout the image. Since the image in the popup is added dynamically and I have control of when its being added, I can do this.
$(document).ready(function(){
$('.ViewImage').on('click',function(){
// some code is executed which brings up the popup
// now we know that the image is added into html we can now run the script
$(".zoomin").click(function (){
//your logic here
});
});
});
2) We have no Clue/ Control when the element is added into HTML but still want to bind a event to it: This is scenario where we have no control on when the element is being added or not sure where it is being added from (might be from some external plugin used etc) or not having control at all on the element which is added. Thats when we use this syntax as suggested by #Rejith R Krishnan
$(document).on('click', ".zoomin", function (){
//Your code.
});
This will work on all the elements which are in the HTML at the time of execution of the script and on the elements which will be added in the future with the class name zoomin. So this script can be placed inside/ outside of jquery document ready event
I have a section on an intranet page that allows for a summary view of Follow-up's a employee has made in relation to customer tickets. We have added a one-click event to delete a particular record by clicking on the standard close icon at the end of each row (has class .fudel) and (value="####"). The deletion is handled by PHP via a POST event. I use the same Jquery that initiates the deletion to reload the summary DIV after sending the POST so that the summary list is current.
The problem is the event will only trigger once, after the .load() has occurred Jquery can no longer detect click events within the dynamic div. If you look at the Jquery I used it uses the .on() method which as I understand it replaced .live() and is specifically intended to deal with event detection in dynamically loaded elements.
$('.fudel').on("click", function() {
var m = $(this).attr("value");
var answ = confirm("Press OK to DELETE follow-up record for: ("+ m +")");
if (answ == true) {
$.post("includes/phpfunctions.php", {
fudelete: m
});
$("#followup").load(location.href + " #followup > *");
}
else {
$.alert('Deletion Canceled', 'User Notice');
}
});
Also, in two recent question I found that a number of these event detection problems hovered around the need to add the second, third, fourth etc. etc. Jquery calls into the "Callback" of the on() event. If that ends up being an explanation for the problem here, I would ask someone to provide a good link to documentation that explains when Jquery actions need to fall within the callback scope vs when it can/should fall outside of the callback scope.
If the load() function is replacing the contents of the table (which includes the .fudel elements) you need to use a delegated event handler. Try this:
$('#followup').on('click', '.fudel', function() {
var m = $(this).attr("value");
var answ = confirm("Press OK to DELETE follow-up record for: ("+ m +")");
if (answ == true) {
$.post("includes/phpfunctions.php", {
fudelete: m
});
$("#followup").load(location.href + " #followup > *");
}
else {
$.alert('Deletion Canceled', 'User Notice');
}
});
Note that the click event is now bound to the #followup element and delegated to any child .fudel element.
Try delegation event, because if you make this:
$('.fudel').on("click", function() {
It attach the event to .fudel if this element exists, but if not exists in the DOM loading, you can make this:
$('body').on("click", ".fudel", function() {
By this mode you target an element that may exists in the future, but not neccesary on DOM ready.
Is there an event handler to use in JQuery when a DOM select element has finished loading?
This is what I want to achieve. It is working with other events except 'load'.
This piece of code is loaded in the head.
$(document).on('load', 'select', function(){
var currentSelectVal = $(this).val();
alert(currentSelectVal);
} );
The question was badly formed earlier. I need to attach the event handler to all select elements, both present when the document is loaded and dynamically created later.
They are loaded from a JQuery Post to a php-page. Similar to this:
$.post("./user_functions.php",
{reason: "get_users", userID: uID})
.done(function(data) { $("#userSelector").html(data);
});
I think we're all confused. But a quick break down of your options.
After an update made to the Question, it looks like the answer you might seek is my last example. Please consider all other information as well though, as it might help you determine a better process for your "End Goal".
First, You have the DOM Load event as pointed out in another answer. This will trigger when the page is finished loading and should always be your first call in HEAD JavaScript. to learn more, please see this API Documentation.
Example
$(document).ready(function () {
alert($('select').val());
})
/* |OR| */
$(function() {
alert($('select').val());
})
Then you have Events you can attach to the Select Element, such as "change", "keyup", "keydown", etc... The usual event bindings are on "change" and "keyup" as these 2 are the most common end events taking action in which the user expects "change". To learn more please read about jQuery's .delegate() (out-dated ver 1.6 and below only), .on(), .change(), and .keyup().
Example
$(document).on('change keyup', 'select', function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
Now delegating the change event to the document is not "necessary", however, it can really save headache down the road. Delegating allow future Elements (stuff not loaded on DOM Load event), that meet the Selector qualifications (exp. 'select', '#elementID', or '.element-class') to automatically have these event methods assigned to them.
However, if you know this is not going to be an issue, then you can use event names as jQuery Element Object Methods with a little shorter code.
Example
$('select').change(function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
On a final note, there is also the "success" and "complete" events that take place during some Ajax call. All jQuery Ajax methods have these 2 events in one way or another. These events allow you to perform action after the Ajax call is complete.
For example, if you wanted to get the value of a select box AFTER and Ajax call was made.
Example
$.ajax({
url: 'http://www.mysite.com/ajax.php',
succuess: function(data) {
alert($("select#MyID").val());
}
})
/* |OR| */
$.post("example.php", function() { alert("success"); })
.done(function() { alert($("select#MyID").val()); })
/* |OR| */
$("#element").load("example.php", function(response, status, xhr) {
alert($("select#MyID").val());
});
More reading:
.ajax()
.get()
.load()
.post()
Something else to keep in mind, all jQuery Ajax methods (like .get, .post) are just shorthand versions of $.ajax({ /* options|callbacks */ })!
Why dont you just use:
$(document).ready(function () {
//Loaded...
});
Or am I missing something?
For your dynamic selects you can put the alert in the callback.
In your .post() callback function, try this:
.done(function(data) {
data = $(data);
alert(data.find("select").val());
});
Ok, correct me if I understand this wrong. So you want to do something with the selects when the document is loaded and also after you get some fresh data via an ajax call. Here is how you could accomplish this.
First do it when the document loads, so,
<script>
//This is the function that does what you want to do with the select lists
function alterSelects(){
//Your code here
}
$(function(){
$("select").each(function(){
alterSelects();
});
});
</script>
Now everytime you have an ajax request the ajaxSend and ajaxComplete functions are called. So, add this after the above:
$(document).ajaxSend(function () {
}).ajaxComplete(function () {
alterSelects();
});
The above code will fire as soon as the request is complete. But I think you probably want to do it after you do something with the results you get back from the ajax call. You'll have to do it in your $.post like this:
$.post("yourLink", "parameters to send", function(result){
// Do your stuff here
alterSelects();
});
Do you want all Selects to be checked when the User-Select is loaded, or just the User-Select?...
$.post("./user_functions.php", {reason: "get_users", userID: uID}).done(function(data) {
$("#userSelector").html(data);
//Then this:
var currentSelectVal = $("#userSelector").val();
alert(currentSelectVal);
});
If your select elements are dynamically loaded, why not add the event handler after you process the response?
e.g. for ajax
$.ajax({
...
success: function(response) {
//do stuff
//add the select elements from response to the DOM
//addMyEventHandlerForNewSelect();
//or
//select the new select elements from response
//add event handling on selected new elements
},
...
});
My solution is a little similar to the posters above but to use the observer (pubsub) pattern. You can google for various pub sub libraries out there or you could use jQuery's custom events. The idea is to subscribe to a topic / custom event and run the function that attach the event. Of course, it will be best to filter out those elements that have been initialize before. I havent test the following codes but hopefully you get the idea.
function attachEventsToSelect(html) {
if (!html) { // html is undefined, we loop through the entire DOM we have currently
$('select').doSomething();
} else {
$(html).find('select').doSomething(); // Only apply to the newly added HTML DOM
}
}
$(window).on('HTML.Inserted', attachEventsToSelect);
// On your ajax call
$.ajax({
success: function(htmlResponse) {
$(window).trigger('HTML.Inserted', htmlResponse);
}
});
// On your DOM ready event
$(function() {
$(window).trigger('HTML.Inserted'); // For the current set of HTML
});
I'm trying to have dynamically loaded content (via the Infinite Scroll script: http://www.infinite-scroll.com/ ) be styled when triggered by an "inview" custom event ( https://github.com/protonet/jquery.inview ).
My code looks like this:
$(document).on("inview", ".attachment-portfoliosmall", function(e) {
if( $.data( this, "styleappended" ) ) {
return true;
}
$.data( this, "styleappended", true );
$(".attachment-portfoliosmall").css('visibility','visible').hide().fadeIn('slow');
$(".attachment-portfoliosmall").parent(".portfoliopreload").css("background", "none");
});
As you can clearly see, the $.data routine is used in order to ensure that the .on() event handler isn't executed more than once for each element in the selection filter.
This code works great in theory, EXCEPT that once the dynamically loaded content on the next page is appended to the document, the .on() routine is being run on every single element a second time, rather than just the newly added elements.
On my website, if you scroll to the next page, you will see all the elements fade out and back in again, which is caused by the .on() event handler.
How can I prevent it from being executed on the previously handled elements on the previous page(s)?
here's what I mean in my comment.
$(document).on("inview", ".attachment-portfoliosmall", function(e) {
var $this = $(this);
if(!$this.hasClass('loaded')) {
$this.addClass('loaded');
$this.css('visibility','visible').hide().fadeIn('slow');
$this.parent(".portfoliopreload").css("background", "none");
}
});
Something like that might work for you.
Is there a way to check if jQuery fired the page load events yet, or do you have to roll your own? I need to alter the behavior of links, but I don't want to wait until the page finishes loading because the user could conceivably click on a link on, say, the top half of the page before the page finishes loading. Right now I'm doing it like this:
var pageLoaded = false;
$(function() {
pageLoaded = true;
});
function changeLinks() {
$("a[data-set-already!='true']").each(function() {
$(this).attr("data-set-already", "true").click(...);
});
// Is there something along the lines of jQuery.pageWasLoaded that I can
// use instead?
if (!pageLoaded) {
window.setTimeout(changeLinks, 100);
}
}
changeLinks(); // Added per #jondavidjohn's question
Since you are using the document ready shorthand, I'm guessing you mean when the dom is loaded. For this:
$.isReady
You could use setInterval and clear the interval on domready:
var changeLinksInterval = setInterval(function () {
$("a[data-set-already!='true']").each(function() {
$(this).attr("data-set-already", "true").click(...);
});
}, 100);
$(function () {
clearInterval(changeLinksInterval);
});
By the way, in your code example, you shouldn't need .each() - you should be able to call .attr() and .click() directly and let jQuery do the looping. Unless there is more to your .each() code that you didn't post.
$("a[data-set-already!='true']").attr("data-set-already", "true").click(...);
you could use .live() to initiate a click event that needs additional work when binding.
$("a[data-set-already!='true']").live(function(){
// since this event will only fire once per anchor tag, you
// can safely bind click events within it without worrying
// about getting duplicate bound click events.
var $this = $(this);
$this
.data("dataSetAlready",true)
.click(myClickHandler);
});
this is also a useful technique for late-initializing plugins on elements that may not exist at domReady.