How can I replace(re-execute ) current script functions? - javascript

I want to replace load script into existing script after ajax response.
Due to I will only update some element so the whole page will not be reloaded, and some event on replaced element will be lost.
Re-Run application Javascript on ajax loaded content <--- This is not a solution for me...
I tried take the script tag from loaded html and eval() them. However, this will not replace the existing functions but double them.
I want to replace, or re-execute the script function by not use $(document).html(data);
I read many references such like,
http://www.javascriptkit.com/javatutors/loadjavascriptcss2.shtml
But I dont very understand it.....
Please help and advice a more easy understanding example. Thank you very much!
My script now is
$script.each(function(index){ //data from loaded page, same page
if(!$(this).attr('src')){ //replace where is not from external only
$(document.getElementsByTagName( 'script' )).slice(index).remove();
//remove existing script, no working
eval($(this).text());
// re-execute, wokring
};
});

You may try to combine your logic to functions and call it when you want. Moreover, if you ajax-loaded content will contains JS functions you can call it after place retrieved html to the page.
When I need to bind events to some dynamically loaded components I implement function like following:
function rebindDynamic() {
$('#elem1')
.unbind() //Or unbind('click') if you want to unbind specific handlers
.click(function (e) { ... });
$('#elem2')
.unbind() //Or unbind('keyup') if you want to unbind specific handlers
.keyup(function (e) { ... });
...................
}
I hope it will helps.

Related

jQuery event not firing (advanced)

For a dynamic added element via ajax or any after page load, I know that we have to use the .on like
$(document).on('click', '#dynamically-added-element', function() {
// do something
console.log('Hello World!');
});
I even wrapped mine with (function($){})(jQuery); to make sure no conflict; and to make sure everything should be run/loaded in proper order, I also have $(document).ready(function(){});.
Now that event was originally meant to run on Page A and it works well, but when I made and try it run on Page B having the same id for the main container and have the same child html, it doesn't work.
So I've done some experiment/tests and both works.
(1) So what I've done, I wrote exact same event listener through my browser's console with just console.log and click the target element, it works!
(2) On the same .js script, I've added exact same event listener with just console.log but wrapped it inside setTimeout(function(){}, 5000);, after 5 seconds, I clicked the target element and it worked!
So my question now is, why my original code doesn't work? Why these tests works? So what's the solution?
Also, my html elements aren't loaded dynamically, it's loaded on page load, generated via server side PHP.
Edit:
This info might be useful.
running in magento
js script is being included on head (that's why $(document).ready is really important).
jquery script is being loaded before my custom script.
Page A and Page B are on different pages.
It's not an ajax generated element nor js/jquery added element on the fly; it's generated on postback with php code
(3) My third experiment works as well. But I don't want this to be my solution if possible, nor using javascript inline onclick. So what I did, I added a whole new script block inside the php file where that 'part' of the page is being included, with exact same code and it works. But the thing is, I have now two identical event listener.
So now I have 2 identical event listener (regardless if the other one doesn't work - only for Page B), 1 from within (internal) and 1 from external .js file.
<script type="text/javascript">
(function($) {
$(document).ready(function() {
$(document).on('click', '#the-container a', function(e) {
e.preventDefault();
var target = $(this).attr('href');
});
});
})(jQuery);
</script>
Just write you document.on outside of the document.ready that should work and comment your "e.preventDefault();". It worked on the fiddle when I changed it.
<script type="text/javascript">
$(document).on('click', '#the-container a', function(e) {
//e.preventDefault();
var target = $(this).attr('href');
});
</script>
jQuery event handlers are attached to the elements themselves not the selector, if you are instantiating an event handler to an element selector before the element has been loaded, it is not attaching a listener to anything.
For example this will not work:
$.get('http://example.api.com',
function(data){
$node = $('<p></p>')
$node.text(data)
$node.addClass('elementToListen')
$('body').append($node)
})
// this gets executed before the ajax request completes. So no event
// listener gets attached
$('.elementToListen').on('click',function(e){'do somthing'})
because the event listener has been set up before any of the elements have been added to the DOM.
While this will work:
$.get('http://example.api.com',
function(data){
$node = $('<p></p>')
$node.text(data)
$node.addClass('elementToListen')
// here it is getting executed after the AJAX request in the
// success callback
$node.on('click',function(e){'do somthing'})
$('body').append($node)
})

JQuery ClueTip with ColdFusion - Javascript $(document).ready() misfire [duplicate]

Yesterday I had an issue where a .on('click') event handler I was assigning wasn't working right. Turns out it's because I was was trying to apply that .on('click') before that element existed in the DOM, because it was being loaded via AJAX, and therefore didn't exist yet when the document.ready() got to that point.
I solved it with an awkward workaround, but my question is, if I were to put a <script> tag IN the ajax loaded content and another document.ready() within that, would that second document.ready() be parsed ONLY once that ajax content is done being loaded? In other words, does it consider that separately loaded ajax content to be another document, and if so, does having another document.ready() within that ajax-loaded HTML work the way I think it does?
Alternatively; what would be a better way to handle this situation? (needing to attach an event listener to a DOM element that doesn't yet exist on document.ready())
To answer your question: No, document.ready will not fire again once a ajax request is completed. (The content in the ajax is loaded into your document, so there isn't a second document for the ajax content).
To solve your problem just add the event listener to the Element where you load the ajax content into it.
For example:
$( "div.ajaxcontent-container" ).on( "click", "#id-of-the-element-in-the-ajax-content", function() {
console.log($( this ));
});
For #id-of-the-element-in-the-ajax-content you can use any selector you would use in $("selector"). The only difference is, only elements under div.ajaxcontent-container will be selected.
How it works:
As long as div.ajaxcontent-container exists all elements (if they exist now or only in the future) that match the selector #id-of-the-element-in-the-ajax-content will trigger this click-event.
Javascript in the resulting ajax call will not be excecuted (by default) due to safety. Also, you can't directly bind event to non-existing elements.
You can bind an event to some parent that does exist, and tell it to check it's children:
$(document).ready(function(){
$(document).on('eventName', '#nonExistingElement', function(){ alert(1); }
// or:
$('#existingParent').on('eventName', '#nonExistingElement', function(){ alert(1); }
});
Always try to get as close to the triggering element as you can, this will prevent unnessesary bubbling through the DOM
If you have some weird functions going on, you could do something like this:
function bindAllDocReadyThings(){
$('#nonExistingElement').off().on('eventName', function(){ alert(1); }
// Note the .off() this time, it removes all other events to set them again
}
$(document).ready(function(){
bindAllDocReadyThings();
});
$.ajaxComplete(function(){
bindAllDocReadyThings();
});
try this, that is not working because your control is not yet created and you are trying to attach a event, if you use on event it will work fine. let me know if you face any issues.
$(document).ready(function(){
$(document).on('click', '#element', function (evt) {
alert($(this).val());
});
});
The answer here is a delegated event:
JSFiddle
JSFiddle - Truly dynamic
jQuery
$(document).ready(function(){
// Listen for a button within .container to get clicked because .container is not dynamic
$('.container').on('click', 'input[type="button"]', function(){
alert($(this).val());
});
// we bound the click listener to .container child elements so any buttons inside of it get noticed
$('.container').append('<input type="button" class="dynamically_added" value="button2">');
$('.container').append('<input type="button" class="dynamically_added" value="button3">');
$('.container').append('<input type="button" class="dynamically_added" value="button4">');
$('.container').append('<input type="button" class="dynamically_added" value="button5">');
});
HTML
<div class="container">
<input type="button" class="dynamically_added" value="button1">
</div>
I'm working on a code-base with a friend that has a similar requirement. The delegated event handler option is definitely best if all you want is to attach event handlers. An alternative, especially if you need to do other DOM processing in your $(document).ready function, is to put the code you want run into a script element at the end of your code. Basically, instead of:
<script type="text/javascript">
$(document).ready(function() {
// Your code here
});
</script>
<!-- rest of dynamically loaded HTML -->
Try swapping the script and the rest of the HTML around so you have:
<!-- rest of dynamically loaded HTML -->
<script type="text/javascript">
// Your code here
</script>
This forces the browser to only process your code once it has loaded every other DOM element in the dynamically loaded HTML. Of course this means you'll have to make sure the inserted HTML does not have unintended UI consequences by using CSS/HTML instead of JS. Its an old Javascript trick from years gone by. As a bonus, you don't need jQuery for this anymore.
I should mention that in Chromium v34, putting a second $(document).ready call inside a <script> tag in the dynamically loaded HTML seems to wait for dynamically loaded DOM to load and then runs the function as you described. I'm not sure this behaviour is standard though as it has caused me great grief when trying to automate tests with this kind of code in it.
JQuery AJAX .load() has a built-in feature for handling this.
Instead of simply $('div#content').load('such_a_such.url'); you should include a callback function. JQuery .load() provides room for the following:
$('div#content').load('such_a_such.url',
{ data1: "First Data Parameter",
data2: 2,
data3: "etc" },
function(){ $('#span1').text("This function is the equivalent of");
$('#span2').text("the $(document).ready function.");
}
);
However, you do not need to include the data argument.
$( "#result" ).load( "ajax/test.html", function() {
alert( "Load was performed." );
});
http://api.jquery.com/load/

Ruby on Rails - JavaScript in dynamically generated partials

I know putting JavaScript in partials is a bad idea because the page will have to load up a new script every time a new partial is loaded. I am aware of and have read this question, but its answer did not work for me (putting the script into app/javascripts/application.js). I think it is because I am working with partials that are dynamically generated onto the page. I think the dynamically generated partial does not react to the script loaded up on the initial page.
For example, I have a "Rule" div with a select input that has a script to do something when the select input is changed. This works for every Rule div that is generated on page load. But then there is also a "+" or "ADD" button which will dynamically generate more Rule divs which do not respond to the script, unless that script is in the partial.
Is there a good way to keep the script out of the partial when the partial is dynamically generated?
JQuery sets listeners on page load (i.e. $(selector).on(etc.)), so it doesn't listen for events on dynamically added elements. There is a way around it, though. You need to use what is called a delegate.
$(document).ready( function() {
$('body').on('change', 'input.selector', function(e) {
// do something
});
});
I'm not sure what your event (here I put change) or selector for the select you are using (here I put input.selector), but if you replace those with the appropriate information, it should work even with dynamically added elements.
You can use JQuery to execute the code only after the document has loaded onto the DOM:
$( document ).ready(function() {
//Call your functions here
});
That way, your JS will have access to whatever is on the page, because you are ensuring that it is fully loaded.
If your divs are not in place on document ready, you can use event delegation, as suggested by ptd. Basically what this means is that you install a handler on a parent div (which will be present on document ready) which says, "hey, when you click on this dynamic div inside of me, call this function".
$('div#master').on('click', 'div.dynamic', function(event) {
console.log("action here")
var $dynamicDiv = $(event.currentTarget) //The current Target is the thing you clicked on, not the parent.
});
If you are adding elements to the DOM using AJAX calls, but want to keep your JavaScript in your assets folder only, here's a quick and clean way to accomplish this.
// /app/assets/javascript/foo.js
// On intial page load
$(document).ready(function() {
yourJavaScriptForPartials();
});
// After a subdomain field is loaded via AJAX
$(document).ajaxComplete(function() {
yourJavaScriptForPartials();
});
function yourJavaScriptForPartials() {
// Insert your javascript here.
};
Now, any JavaScript you put in the yourJavaScriptForPartials() function will be available both to the initially loaded DOM, and to any DOM elements added via AJAX. For reference, here is the JQuery page for the ajaxComplete event listener.

How to avoid multiple loading of jQuery functions?

I am using following code on my page which I am loading in ajax.
$(document).ready(function() {
$('#button_id').click(function() {
//Do Something
});
});
Now When I click on the button action happens multiple times. I know that its happening because I am loading the ajax page multiple times.
Please help me solve this.
You can use .off() to remove existing listeners:
$(function() {
$('#button_id').off('click').click(function() {
//Do Something
});
});
If I am wrong about your implementation I apologize. Your problem may exist because the binding is created on first page load and then on subsequent ajax loads with new scripts being inserted and creating duplicate bindings. You should prevent any bindings from being generated on ajax loads to prevent duplicate bindings unless you are good with cleanup.
If the button you are clicking on exists in the ajax loaded area then you should use delegation to ensure that the click handlers still work.
For example:
$( "body" ).on( "click", "#button_id", function() {
//do something
});
This will add a binding to the body element, but more specifically to the id #button_id. A click event on the button will propagate and bubble up to the body element (or whatever parent element you choose).
This makes it so that dynamic elements can be inserted in the DOM and only one event handler is needed to listen for it.
No need for .on() or .off() calls for individual ajax loads. This allows your bindings to be much cleaner.
Of course, if your button is not likely to exist on the page all the time then it would not be a good idea to keep extra bindings. Only create these types of binding if they are always needed to prevent optimization issues.
A cleaner solution would be to remove that code from the ajax loaded HTML and use one single event handler in the master page
I guess your problem is the event is firing many times.
To fire only once try this:
$(document).ready(function() {
$('#button_id').on("click",function(e) {
e.preventDefault(); // This prevents the default non-js action (very used for anchors without links or hashes)
e.stopPropagation(); // Prevent the bubling of the event and spread more times
//Do Something
});
});
If doesn't work with e.stopPropagation(); try with e.stopInmediatePropagation();
Adding documentation for the last method I suggested. It could solve your problem.
http://api.jquery.com/event.stopimmediatepropagation/

Links added via ajax do not have the same behavior as links present in the initial DOM

I am using this to generate an AJAX call when user clicks on link.
$('a').not('.noajax').click(function(event) {
event.preventDefault();
AJAXLoad($(this).attr('href'));
});
AJAXLoad is used to generate new content to some DIV. The thing is that when I generate new content which has links, the newly generated links do not behave the way I expect from the above code.
I know this might be caused by the fact that the newly added content doesnt have the old property (encountered similar problem with shadowbox addon image links), but I am not skilled enough in JS to modify my code so that it works. Any help?
You need to use event delegation.
$(document).delegate("a:not(.noajax)","click",function(e){
// do stuff
})
or for 1.7.2+
$(document).on("click","a:not(.noajax)",function(e){
// do stuff
})
You should also replace document with whatever element you are using as a target for AJAXLoad.
$.click(function() {}) only applies to elements that exist on the page when that line of code is evaluated.
You want to use $.live('click', function() {})
$.live() will watch for any new elements that appear that it should apply to.
Edit: spelled out explicitly -
$('a').not('.noajax').live('click', function(event) {
event.preventDefault();
AJAXLoad($(this).attr('href'));
});

Categories