Dynamically reload elements and read their new attributes in JQuery - javascript

I have an Ajax call that returns a piece of html code that is supposed to replace old html code on the page, giving them new attributes. After I successfully dynamically change my elements, I want to run another piece of JS code that reads and uses some of the attributes of the dynamically reloaded elements. However, JS prefers to read the old data (as if it's running synchronously).
The only workaround I've found is to set a timer, but the timer's delay time has to be relatively high (300 ms) to guarantee that it's always done correctly. What is the right way to do this?
Here is a pseudo-code for what I have right now. It works but the 300ms delay time is terrible.
$.post( "ajax/test.html", function( newCode ) {
$("#myDynamicDiv").html(newCode);
setTimeout(function(){
//Use the data that was just stored in #myDynamicDiv
},300);
});

For me I use .promise().done() may be it'll work with you
$("#myDynamicDiv").html(newCode).promise().done(function(){
// your code here
});
Edit: To someone who'll comes here later ..While my code isn't working with Mohasen he find a solution himself .. Please find his answer below

I accepted Mohamed-Yousef's answer, but since that did not include the full answer, here is the full version of what I eventually did:
A JQuery ajax call always returns a "Deferred" object when it's called. You can use this object's "then()" method to run things after the ajax call is finished. Here is the code:
dfrd = $.post( "ajax/test.html", function( newCode ) {
$("#myDynamicDiv").html(newCode);
});
dfrd.then(function(){
//Anything that is here is guaranteed to happen after the Ajax call is done.
});

Related

Javascript: Variable scope and usage order

I came across a peculiar issue when trying to make an ajax call and isolate the actions of the function to itself. Here is the code snippet
$(document).on('click', 'input.action', function(event) {
var self = this;
$.ajax({
url:'http://date.jsontest.com/',
method:'GET',
cache:false,
dataType:'json',
success:self.process,
error:function(){self.process(false);}
});
self.process = function(data) {
if (data) {
alert(data.time);
}
else {
alert("Operation Failed!");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="container">
<input type="button" value="Get Time" class="action"/>
</div>
Let me briefly explain what I am trying to do, on click of the button, I wish to receive some data from the server and display the data. I am using a process function to process the received data. In case of an error I reuse the process function in a different way to display the error message. I simply use the self variable to contain all the elements within the parent function. I fully understand the following:
What I know
I do not have to use the self to contain the process function because another method will not have access to it
Because the process method in the snippet above is declared after the ajax call for the program as far as it is concerned the process function is undefined.
I clearly know how to fix it.
Experiment:
Click on the Get Time button
Wait for as long as you want but see no result, which is expected because of the process function is declared after the ajax call
Click on the Get Time button again
It works now! Some time (which is probably not your time :P) is displayed now!!
What I wish to know:
What just happened? why does it work the second time and everytime after? Remember this only works for ajax calls, if it were the case that the assignment is retained in the function after calling it once, then this should work in every situation but it does not. Here is an experiment to show that it does not work the same way when ajax calls are not used: Fiddle - Experiment
The Solution:
I am adding a sample solution based on #Felix Kling's answer below. In the Sample Solution, there are two buttons Get Time and Get Date. I've attached the parameter to retrieve time in case of Get Time and date in the case of Get Date to the object self and it is interesting that once I click on Get Time nothing happens just like before but if I click on either Get Time or Get Date the second time only time is displayed.
What just happened?
In a simplified way, this:
var process;
// First click
ajaxCall(process); // process is still undefined
process = function() { ... };
// second click
ajaxCall(process); // process is defined
process = function() { ... };
The assignment to self.process "persists" between events because self refers to the same element.
Here is an experiment to show that it does not work the same way when ajax calls are not used: ...
It doesn't work in your fiddle because of one big difference: you are trying to execute process immediately. But it doesn't exist, so an error is thrown. At this point the script terminates and won't execute the rest of the function, where the function definition takes place.
In your example here, the execution of process is delayed. The script "doesn't know" that there is no function to call until the response was received.
There is nothing "special" going on here. Yes, accepted that the first time it returns undefined as it is yet to be defined.
But, you're attaching the function to the same element input.action. So, the next time, when you click the button, this already has the process method attached to it, so gets called when clicked again.
Try adding one more button with same class and click each once. Now though you've clicked the first button, clicking the second button will still not create an alert as it has not yet had the process function attached to it.

Jquery DOM events called after events following it are executed

I am facing a very weird issue in chrome.
My code is
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
The text and the hidden class are being removed after the post action has been executed.
The code is working fine in firefox.
The only thing needed was
Server.async = true
before the server call.
Asynchronous functions fire in order of appearance but return in order of when they finish. It would be odd for those simple text and removeClass methods to return more slowly than whatever you're doing with your Server object, but I suppose it's possible. If you need the first two lines to happen before the postService, you might try jQuery's deferred.promise. Here's a fiddle demonstrating the potential, and some code to inspect:
function firstThing (){
var dfd = new jQuery.Deferred();
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
dfd.resolve();
}
$.when( firstThing() ).then(
function() {
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
}
)
As a side note, the logic of your code is problematic in that by setting the text of #import, whatever img had the hidden class won't be there anymore, but that might be beside the point.
Update
Noticing your response to my comment asking about your use of ajax, I would suggest you read about the async option and see how what you're doing might or might not be blocking events.
I would also recommend reading about jQuery ajax callbacks, particularly error, success, and complete (now, with jQuery 1.8+, fail, done, and always).

Ajax requests ASAP right before </body>, or on document ready too?

I'm optimizing a page, but I can't tell the difference in results between these (the first one is obviously faster, but I'm not sure if it slows the rendering of the page a little or something):
This one will start the request ASAP, and modify the DOM on document ready:
<script>
$.ajax({
url: '/some-url',
success: function() {
$(document).ready(function() {
// do something
});
}
});
</script>
</body>
This one will start the request on document ready:
<script>
$(document).ready(function() {
$.ajax({
url: '/some-url',
success: function() {
// do something
}
});
});
</script>
</body>
Which one is recommended?
Best practice here is to start the Ajax request as soon as possible, but start modifying the DOM only when the document is ready (DOMContentLoaded). To do that, you might use jQuerys Deferred objects which are wired up with jQuerys extended jXHR objects.
<script>
var req = $.ajax({}),
docReady = jQuery.Deferred();
$(function() {
docReady.resolve();
});
$.when( req, docReady ).done(function( data ) {
// read the returned data and modify the DOM
});
</script>
It would be a waste of time to wait for starting the request until the DOM is ready. The XHR request has no business and interest in whats going on with the DOM.
It just makes more sense to decouple those two things entirely. If for some reason the DOM needs a very long time before its ready, you didn't waste the time to let the HTTP request run and collect its data. The other way around, if the request is very slow, you would waste time aswell. So your current snippets are like
DOM ready
-> XHR request
-> Do something useful
Whereas my example is like
DOM ready
XHR request
-> Do something useful as soon as the DOM and request are ready
Since $.ajax doesn't depend on the DOM in any way, there's no reason why you can't call it as soon as possible. In that case, I would put it in the <head> section and call it as soon as its dependent script/script files are done (meaning at least jQuery library). Firing the AJAX request sooner means the response has the ability to come back sooner - it may not be the case that it actually happens, but that's not important.
Checking to sure the DOM is ready inside of success is necessary for you, and it's the quickest way for your code to execute. Using $.when( req ).done(function () {}) creates 2 more jQuery method calls that may or may not significantly delay the execution of your success code - it will delay it, but it will probably be insignificant.
Also, your example where you use document.ready in your success method creates the possibility that the DOM is ready and can execute immediately (in the case that the AJAX request completes before the DOM is fully loaded, which I wouldn't expect). In jAndy's example where document.ready runs immediately after $.ajax, it guarantees that it will bind an event handler for the document being ready...which means it has to be stored (causing the DOM to be ready later) and then looked up later when the event occurs, and executed. Again, the difference is possibility vs. guarantee...and all is probably insignificant (as long as you don't use your second example).
In this simple example, both versions should do. Which one is better depends on your page and other scripts.
If your script is a little more complex, and you need to pass data to the ajax-request which has to be fetched from the page, and your page is not ready at that moment - you will have an error.
Another thing is, that any script on your page will block the browser while it is processed, so a more complex code without doc-ready around it may lead to a short stop in the page-render-process.
In most cases I prefer to let the browser to load all HTML, CSS and the JS - and after that start my progressive enhancement and loading of additional content.
But again - in this simple case - I don't see much of a difference.

Run js when document is changed?

I tried looking for the answer, and this is my first post, so bear with me if I mess up in some way.
Basically my problem is this: I'm writing an extension for Chrome that uses jQuery. I have another extension that makes a timed $.ajax() request every 10 seconds. I need to find a way to run my code every time that timed ajax request and its callback function completes. Setting a timer for my own script can be done, although that's rather half-assed and doesn't work as well.
The problem can be illustrated thus:
//extension 1
function timedFunc() {
setTimeout(doStuff, 10000);
};
timedFunc();
//extension 2
//code to be run every time doStuff completes
I feel like there may be a very elementary solution to this problem but I appreciate the help.
There is (was) an event called DOMSubtreeModified.
But it has been deprecated so at tho moment there are really only workarounds available.
Why is the DOMSubtreeModified event deprecated in DOM level 3?
I can't advise on using this event as it hasn't even been implemented in all browsers.
But what you can do (easily) is just trigger you own event with all your ajax call!
Example:
fire your event when (any) ajax call completes:
$(document).ajaxComplete(function() {
$(document).trigger('domChanged');
}
and listen to it:
$(document).on('domChanged',function() {
alert("i changed the DOM tree!");
});
btw:
taken that you just want to react to ajax calls compleing... just use the .ajaxComplete() event:
http://api.jquery.com/ajaxComplete/
i didn't really understand what you are trying to say but i did understand your question in the title so here is my modest answer:
// a global variable for the documents content
var content=document.documentElement.innerHTML;
// return true if the document content has changed
function documentChanged(){
return content==document.documentElement.innerHTML;
}

editableText plugin enabling problem

I've been experimenting with this plugin http://valums.com/edit-in-place/, so far so good... But i ran into this problem. I want to update my page when update or new request to save data is sent but if i update this function(edit-in-place) it will add second set of buttons, third, fourth and so on. How could i tell it that it would update just on that returned data, but not all elements? I have an idea it has to do something with each function of jquerys, but I'm not sure as I'm quite new to jquery. Thanks for any help!
You can give the selector a context, so for example if you're doing this now:
$('.editableText').editableText({
newlinesEnabled: false
});
In your ajax callback, give it a context when calling it in the success or complete method, wherever you're adding elements, like this:
$.ajax({
...options here...
success: function(data) {
$('.editableText', data).editableText({
newlinesEnabled: false
});
//insert the elements somewhere...
}
});
The , data gives it a context (you can see options for $(selector, context) here), this means it's only searching for elements of that class within the returned data/html, not all elements on the page. This should eliminate your repetition issue of it selecting and running the plugin on elements it's already run on.

Categories

Resources