I want to know what's the best practise for updating DOM after an Ajax call.
For example, imagine we have a list of users and we can add a user with a form which make an Ajax call to insert the user. After the form is submitted and the user added in database, the DOM is edited to add HTML without refreshing the page (with the Ajax success event).
I see two possibility to make this :
Make an Ajax call who add the user in db and return all the DOM structure with html tag, etc.
Make an Ajax who add the user in db and return all the data of an user and create the DOM element in Javascript
What'is the best way to do it (or another way) ?
You can add elements to the DOM with document.createElement(). Then use the innerHTML property to add content to the element. Finally append the element to another with .appendChild().
There is no better way between the two options. You can either prepare your HTML structure in the backend and import the written HTML and directly append it with JavaScript or create the elements frontend in JavaScript.
Here are the main advantages to using the latter:
it's easier to debug JavaScript than PHP (PHP files targetted by AJAX calls are quite hard to debug and to maintain).
returning an object with AJAX instead of an HTML string is easier to use and more maintainable. You can have an API to handle the data. PHP only returns a JSON object.
if JavaScript handles the creation of elements, you can save those in variables. Sometimes, I find it useful to save an HTMLElement in a JavaScript variable so I can later access it to change its properties without having to go through selectors (querySelector() and others).
I would go with the second option
Make an Ajax who add the user in db and return all the data of an user and create the DOM element in Javascript
Breaking it down like so to improve on readability and maintenance
Add action to AJAX that is linked to a function on the backend, (i.e PHP, Python) that does the DB update and more.
Create the Element structures in Javascript (You can maintenance uniformity with other structures on your page). And wrap it in a function.
document.body.onload = addElement;
function addElement ($newuser) {
// create a new div element that would contain user record
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode($newuser);
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("user-container");
document.body.insertBefore(newDiv, currentDiv);
}
Related
I am working on a project where i need to get a specific element from an external html file as a string in my jQuery.
As i understand the .get(); function cannot get a specific element (by class or ID) and the .load() can, but loads it directly into the dom of the file.
Is there another function or a way to go about this?
What i need to do is get a specific html element and replace some macros in it with data from an object and then append it to an element (multiple times.) Therefore i cannot just load it in and replace the macros afterwards.
You can .get it and then only subselect.
$.get('myfile.html', function(response) {
var inside = $(response).find('#inner-id');
// do stuff with inside...
});
This is my jquery scenario:
User click on div
It triggers an ajax call to save some data on DB
when callback received, we show an update msg <--everything good
until here
Now, when user click on the same element, it shows the information
from the DB, the same should happen with the other divs!
Noticed that when you click, the same text that you saved later is showing up in all the divs!!! it is not refreshing, but the actual source IS showing
the changes!
It looks like only the DOM is not reflecting the changes!
I am trying to put the text in the divs using .text();
All the divs are using the same element id!, I am just updating its data!
Thanks,
Marco
All the divs are using the same element id! - never ever should two elements have the same ID, because it breaks the principles on which HTML is built on and 3rd party libraries rely on.
If you need to target multiple elements use classes.
In case your elements have the class yourClass and you want to set them the text "foo", then
var yourResponseText = "foo";
$('.yourClass').text(yourResponseText);
Especially if you use jQuery - the ID selector is implemented in such way, that when it finds an element with that ID it doesn't look for another - the settings will only affect the first (from the viewpoint of DOM) element. On the other hand, when you're using the class selector, then simply said you're doing a forEach cycle through the elements with that class.
I have a popup plugin which sets the html content of a <div/> with the response of an AJAX call.
Every time i open the popup, in the code i just call $("#popup").html(response). This overrides the existing html content with the new content.
Should i call $("popup").empty() before i call $("popup").html(response) so i release the browser memory used by the objects which were previously in the $("popup") div? (eventually prevent memory leaks)
PS: what if i call $("popup")[0].innerHTML = response ? should i call .empty() method?
Short answer no.
jQuery.fn.html uses DOMNode.innerHTML = after doing several other things. One is to remove any stored data on nodes (stored via $.fn.data), see http://james.padolsey.com/jquery/#v=git&fn=jQuery.fn.html for full source overview.
.innerHTML removes the children and replaces with the new html. But beware of memory leaks. I would use jQuery.fn.empty before setting innerHTML. eg.
var a = document.createElement('div'),
b = document.createElement('div');
b.appendChild(a);
b.innerHTML = 'new innerHMTL'.
You would think everything is ok. But the node replaces/removed is still captured in the varible a and therefore isn't thrown to the garbage collector. I'm not sure wether or not that jQuery stores DOMNodes internal until you call jQuery.removeData etc.
JQuery documentation of html method says:
When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content. Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.
So you don't need to call empty().
No need to call empty().html(response) method ovverides the existing content.
No difference except .empty() runs faster and .html() can overwrite the content of the context
http://jsperf.com/jquery-empty-vs-html/17
I'm developing a website that allows users to open multiple pages of the same content in the same browser window via inline 'windows'.
As the content can be repeated multiple times the id's can in turn be the same and therefore I have to "handle" them each so that I can distinguish between these pages.
I currently do this by assigning on load a unique id to the script like so:
var id_key;
function load_page() {
id_key++;
load_script("test.js") //load javascript file
}
//test.js:
$(function () {
var unique_id = id_key;
//adds the `unique id ` to the end of all elements with an id attribute set. ie `mycontainer` becomes `mycontainer_1`
update_ids(unique_id);
$("#mybtn_ " + unique_id).click(function () {
//do stuff
});
}
This works fine most of the time however if multiple pages are loaded too fast the Id tends to get overwritten causing confusion and errors.
I am wondering if there is a better technique of this doing this. I have heard of backbone.js but I am not sure whether that would be helpful in this case.
There are several general approaches to solve this kind of problem:
Load the sub pages in iframes. Each iframe gets it's own ID space. Scripts in all frames can talk to each other via the parent variable as long as all documents were loaded from the same domain.
Don't use any ids. Instead, give each "window" an ID and then locate elements in the window via classes and parent-child relations. Note that an element can have more than one class.
You can then use $(selector, win) to look for elements on a certain window win. The window becomes the "Selector Context" which means jQuery will search only children of the window and nothing else.
At the start of your script, locate all important elements by ID and save them in a JavaScript object. That way, you can access them without using a jQuery selector.
For example, you could select anything with an ID and save it with .data() in the window element. After this setup, all elements would be accessible via $(win).data('id')
You can generate quite good unique ids by concatenating a date and a random number:
new Date().getTime() + Math.random()
While this is by no means perfect, I think in your use case it will suffice.
As Jack mentioned in his comment, you can pass this id to your new window as a get parameter. I once did a whole OS-like interface with this method, and it worked flawlessly.
I have any number of anchor links on a page that need to execute the same block of JavaScript code on click, and that code needs to be associated with one value. There are several of these on each page. I usually use a hidden input to store the value in a one-to-one relationship, but what is the best way to associate several links placed throughout a page with a value?
For example, think of a group of links that reference a product by ID, and all show the same dynamic layer for the product. Now there might be a multiple groups of links for a bunch of products. How do I draw those associations? I'm using Mootools and bind events by class, so I don't want a bunch of inline event function calls that pass arguments.
If your already using Mootools, a good way to do this is using the element's data storage.
window.addEvent('domready', function() {
$$('a.classname').each(function(el) {
el.store('productID', /*get this however you want*/);
el.addEvent('click', function(e) {
var productID = el.retrieve('productID');
}
}
}
And here's one method for getting the productID's (assuming you have control over URL formatting):
<a href='ViewProduct.php?ProductID=7#pid:7'>link</a>
//in your js (above)
var pid = el.get('href').split('#')[1].split(':')[1];
el.store('productID', pid);
Do you want to set the values in your html code? Otherwise, you can dynamically add the values to the dom nodes themselves.
If you want to set them in the html, use a custom attribute if you don't care for standard compliance. If you do care, encode the values as class names or use the lang-attribute and prefix your data with 'x-' so you stay compliant to RFC 1766.