With jQuery (Selector works)
elem = document.getElementById('container');
$(elem).load('file.html');
Without jQuery (Selector doesn't work)
elem = document.getElementById('container');
elem.load('file.html');
How can I execute functions on an element without jQuery?
The load() function is already created and I'm able to execute the load() function on $(elem) but not on elem.
load is a jQuery function, so without jQuery, it does not exist. But you could create your own:
Object.prototype.load = function (src) {
var request = new XMLHttpRequest(),
elem = this;
// Make a request to the provided URL
request.open('GET', src, true);
request.onload = function() {
// When it is loaded
if (request.status >= 200 && request.status < 400) {
// Insert it in the DOM element
elem.innerHTML = request.responseText;
}
};
request.send();
};
// Example usage
var elem = document.getElementById('container');
elem.load('content.html');
You use the DOM API (spec | MDN) and various other associated APIs. That specific example is rather more work, as you have to query the resource via XMLHttpRequest (spec | MDN), then assign the HTML you've loaded to the innerHTML of the element.
Related
EDIT: made title more specific to address duplicate question problem.
I have an HTML page that has a button and a div. When the user clicks the button, a function runs an XMLHttpRequest to get a table from an XML file. The table should be inserted into the div.
The AJAX request returns an object Element to my variable. How can I get the content of that variable (i.e., the <table><tr><td>... etc. from the XML file) to insert into the div?
Here's the JavaScript:
function table_loadContent() {
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
console.log("HTTPRequest");
} else {
request = new ActiveXObject("Microsoft.XMLHTTP");
console.log("ActiveX");
}
request.open('GET', 'myXMLFile.xml');
request.onreadystatechange = function() {
if ((request.readyState === 4) && (request.status === 200)) {
var newTable = request.responseXML.getElementsByTagName('table');
document.getElementById('myDiv').appendChild(newTable);
}
}
request.send();
}
Variations that I've tried that don't work:
document.getElementById("myDiv").innerHTML = myVar;
document.getElementById("myDiv").appendChild(myVar);
document.getElementById("myDiv").appendChild(myVar[0]);
same as above but using a second variable to hold a .toString() version
tried declaring the XML file as XML and as HTML
var newTable = request.responseXML.getElementById('myTable');
In the next code:
var newTable = request.responseXML.documentElement.getElementsByTagName('table');
The newTable variable is an HTMLCollection, it is not an element.
If you want to append just the first element in the collection you can use:
document.getElementById('myDiv').appendChild(newTable[0]);
If you want to add all the nodes inside the collection you need to iterate in the collection and add to the div each element contained in it:
var newTable = request.responseXML.documentElement.querySelectorAll('table');
var myDiv = document.getElementById('myDiv');
[].forEach.call(newTable, function (table) {
myDiv.appendChild(table)
});
NOTES:
1 - I've used querySelectorAll method because it is a not-live HTMLCollection and can be used to modify the DOM without modifying the collection.
2 - Use the documentElement property of the responseXML to ensure that you are selecting the main document node.
We discovered the solution:
By changing the lines:
var newTable = request.responseXML.getElementsByTagName('table')
document.getElementById('myDiv').appendChild(newTable)
to:
var newTable = request.responseText
document.getElementById('myDiv').innerHTML = newTable
it works as we'd like it to. (Edit frustration: I can't get it to break lines properly)
I'm trying to use an AJAX call to update a bunch of image elements on a page. The list of elements to update is held in an array and the URLs to assign to each image are retrieved from a PHP page via AJAX.
The code I have below doesn't work because imagesArray[i] is undefined when it is called from the callback function in the AJAX call - due to the asynchronous nature of JavaScript presumably.
var imagesArray = document.getElementsByClassName('swappableImages');
for (i = 0; i < imagesArray.length; i++) {
var requestUrl = "http://example.com/getAnImageURL.php";
getDataViaAJAX(requestUrl, function(data) {
alert('img url=' + data.responseText);
imagesArray[i].src = data.responseText;
});
}
function getDataViaAJAX(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
On reading around it seems that one way to solve this would be to use a closure, however closures are something I've still not managed to get my head around and the examples I have found have just confused me further.
So, how can I update each element in the array as an when the AJAX function returns?
Note that the 'duplicate' question that has been identified is a jQuery version of the question with jQuery specific answers. I am using vanilla JavaScript.
Note: First example/approach - referred to in comments - removed from answer.
You may try this:
var requestUrl = "http://example.com/getAnImageURL.php";
for (i = 0; i < imagesArray.length; i++) {
(function(j) {
getDataViaAJAX(requestUrl, function(data) {
alert('img url=' + data.responseText);
imagesArray[j].src = data.responseText;
});
})(i);
}
I am doing a project where I do not use jQuery.
I am trying to load posts from new pages with Ajax, but I don't know how I should extract a specific HTML element or content inside a specific HTML element from the returned string, properly.
Here is how the HTML (for the part I am trying to load new contents into) looks like;
<div id="posts">
<div class="post"> 1 </div>
<div class="post"> 2 </div>
<div class="post"> 3 </div>
<div class="post"> 4 </div>
<div class="post"> 5 </div>
<!--posts-->
</div>
<div id="loadmore">Load More</div>
Here is a sample of how the script I tried looks like (it works);
function load(path) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
var resp = req.responseText;
var cont = resp.slice(resp.indexOf('id="posts">') + 11, resp.indexOf("<!--posts-->"));
document.getElementById("posts").innerHTML = document.getElementById("posts").innerHTML + cont;
}
}
req.open("GET", path, true);
req.send();
}
var page = 1;
document.getElementById("loadmore").onclick = function () {
page++;
var pathToLoad = "/page/" + page;
load(pathToLoad);
}
I feel like I am doing it the worst way, and my question is how do I load contents that is inside "#posts" from the new page in a better way?
Thank you!
If i understood what you're looking for, you could create a new element and insert the responseText into that element.
function load(path) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
var resp = req.responseText,
d = document.createElement('div');
d.innerHTML = resp; // This way you have a dom node you can easily manipulate or iterate through
for(var i = 0; i < d.getElementsByClassName("post").length; i++){
var el = d.getElementsByClassName("post")[i];
console.log(el.innerHTML);
//Do stuff with the element you need to append.
}
}
}
req.open("GET", path, true);
req.send();
}
Using createElement function you have a Element object, that you can easily use and manipulate for your purposes. Here is the reference for the element object.
https://developer.mozilla.org/en-US/docs/Web/API/Element
It's been almost a month, I was busy with other works, that is why I am late. This project is my favorite though. The big part of the project is also focused on animations, working on that (in JavaScript).
I have learned a lot about "practical JavaScript" in the past month (I was lazy with jQuery before), I made a small library to avoid a lot of repetitions, mostly I will still use native JavaScript 'cause it's cool. My library is a compliment to the JavaScript for my project, not being lazy again - Oh no.
Also never going back to jQuery again or use anything I do not understand hundred percent. Sticking to my rules.
This is what I made after the help from #gmast. It works, and I am satisfied now.
function load(path) {
var rUrl = path.substring(0, path.indexOf(" ")),
rSelector = path.substring(path.indexOf(" ") + 1),
req = new XMLHttpRequest();
req.open("GET", rUrl, true);
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
var nDoc = document.createElement('div'), nElem, length, i;
nDoc.innerHTML = req.responseText;
nElem = nDoc.querySelectorAll(rSelector);
length = nDoc.length;
for (i = 0; i < length; i += 1) {
document.getElementById("posts").appendChild(nElem[i]);
}
}
};
req.send();
}
Then I call it like;
var pageNumber = 1;
document.getElementById("loadmore").addEventListener("click", function () {
pageNumber++;
var pathToLoad = "/page/" + page + " #posts > .post";
load(pathToLoad);
});
Explanation:
The reason I changed getElementsByClassName to querySelectorAll is because I am going to use it for some more things, and the actual code I have to use in the project is more complex with callbacks and a lot of different objects. I would prefer getElementsByClassName as suggested by #gmast, if I did not have to use this function for multiple different things.
Getting the length of the elements out side of the for loop is important, it creates bugs otherwise, because here I am removing one element with every loop. Optionally do not use increment (that is do not use i++, i += 1 etc) to solve the problem.
If you see my comments under #gmast's answer you will see I was talking about getting "[object HTMLDivElement]", that is because innerHTML accepts HTML not objects, and also my point was about the numbers.
I was noob about most part of JavaScript that is connected with the DOM. Now I am better.
I'm taking a class on Ajax and this very simple script is throwing an error I don't understand. I keep getting an Uncaught Type Error saying that the appendChild method is not a function.
The function I'm working through is meant to asynchronously load the contents of a text file into a 'p' tag when the link is clicked.
I'm somewhat new to javascript so it's probably something simple I've missed, I'd appreciate any help in understanding what I'm doing wrong.
(function(){
var link = document.getElementsByTagName('a')[0];
link.onclick = function(){
//create xhr object
var xhr = new XMLHttpRequest();
// handle the "onreadystatechange" event
/*
xhr.readysState property values
0 = Uninitialized
1 = Loading
2 = Loaded
3 = Interactive - server is sending a response
4 = Complete
*/
xhr.onreadystatechange = function() {
if ( (xhr.readyState == 4) && (xhr.status == 200 || xhr.status == 304) ) {
xhr.responseText;
var body = document.getElementsByTagName('body')[0];
var p = document.getElementsByTagName('p');
var pText = document.createTextNode(xhr.responseText);
console.log(p);
console.log(pText);
p.appendChild(pText);
body.appendChild(p);
}
};
// open the request
/* arguments:
1. type of request a (GET or POST)
2. path
3. asynchronaus request? (true || false)*/
xhr.open('GET', 'files/ajax.txt', true);
// send the request
xhr.send(null)
return false; // disable default behavior of link
};
})();
I've created a jsFiddle to show my code:
http://jsfiddle.net/scottm1164/656edjsf/
getElementsByTagName returns a NodeList. Therefore, you have to access individual items with an index like
var p = document.getElementsByTagName('p')[0];
The reason it was giving you
p.appendChild is not a function
is because appendChild is not a function of type NodeList
p is a NodeList; I think you meant document.createElement rather than document.getElementsByTagName.
var p = document.createElement('p');
p is an array of elements. You should select just one. In your fiddle, you don't even have 1.
i have javascript code that does these things in a loop
create a div element,append it to the dom and get its reference
pass this reference to a function that makes an ajax post request
set the response of the ajax request to the innerHTML of the passed element reference
here is the code
window.onload = function () {
var categories = document.getElementById('categories').children;
for (i = 0; i < categories.length; i++) {
var link = categories[i].children[1].children[0].attributes['href'].nodeValue;
var div = document.createElement('div');
div.className = "books";
div.style.display = "none";
categories[i].appendChild(div);
getLinks(link, div);
}
}
function getLinks(url, div) {
xhr = new XMLHttpRequest();
xhr.open('POST', 'ebook_catg.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
url = encodeURIComponent(url)
var post = "url=" + url;
xhr.node=div; //in response to Marc B's suggestion
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
xhr.node.innerHTML = xhr.responseText;
xhr.node.style.display = "block";
}
}
xhr.send(post);
}
now when i check this in firebug i can see that the div element is created and appended to the categories element and its display is set to hidden. also the ajax post requests are being sent and the response is being received as expected. But the innerHTML property of div is not set and neither its display is set to block.
This means that the function getLinks loses the div reference.
when i type console.log(div) in the firefox console it says ReferenceError: div is not defined.
can somebody explain whats going on here?
in response to Franks's comment i changed readystate to readyState and i am able to attach the response of the last ajax request to the dom. so that makes it obvious that the div reference is being lost.
Thats because you are using a public (global) variable div that keeps getting overwritten.
Try this in your for loop:
for (i = 0; i < categories.length; i++) {
var link = categories[i].children[1].children[0].attributes['href'].nodeValue;
var div = document.createElement('div'); //USE var!
div.className = "books";
div.style.display = "none";
categories[i].appendChild(div);
getLinks(link, div);
}
Remember that the response handlers innards aren't "fixated" when the callback is defined, so the 'current' value of the div var doesn't get embedded into the function's definition. It'll only be resolved when the function actually executes, by which time it might have been set to some completely other div, or been reset to null as the parent function's scope has been destroyed.
You could store the div value as a data attribute on the xhr object, which you can then retrieve from within the callback:
xhr.data('thediv', div);
xhr.onreadystatechange = function () {
if (xhr.readystate == 4) {
div = xhr.data('thediv');
etc....
Ok, you've got a few globals going on that you don't want. Rule of thumb: unless you need to access a variable outside of a function, place var in front of it. Otherwise you'll have data clobbering itself all over the place:
// changed the name to `d` because div seems to already be a global var.
function getLinks(url, d) {
// make xhr a local variable so it won't get re-written.
var request = new XMLHttpRequest();
request.open('POST', 'ebook_catg.php', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
url = encodeURIComponent(url)
var post = "url=" + url;
request.onreadystatechange = function () {
// when the request was global, this would be false until the last
// request completed
if (request.readyState == 4) {
// since d only exists as a parameter to getLinks, this should
// already be bound when the onreadystatechange is created.
d.innerHTML = request.responseText;
d.style.display = "block";
}
}
request.send(post);
}
So, why did I just do such strange, strange things? Well, it looks like div was being assigned as a global variable and while JS should always look to function parameter name for binding, we want to eliminate all possible problems. So I changed the name of that variable. Then I set xhr to reflect a local variable with the var keyword. I also changed the name to request. Once again, it shouldn't matter -- var means that the variable will be bound to that scope, but the change is harmless and since I don't know what else you have, I decided to remove ambiguities. If it does not help JS, it will at least help the reader.
NOTE:
The important part of the above answer is var in front of request.
here i am answering my question.The following code works,i mean the response from each post is appended to the corresponding div element.
var xhr=new Array();
window.onload=function() {
var categories=document.getElementById('categories').children;
for(i=0;i<categories.length;i++)
{
var link=categories[i].children[1].children[0].attributes['href'].nodeValue;
var div=document.createElement('div');
div.className="books";
div.style.display="none";
categories[i].appendChild(div);
getLinks(link,div,i);
}
}
function getLinks(url,div,i)
{
xhr[i]=new XMLHttpRequest();
xhr[i].open('POST','ebook_catg.php',true);
xhr[i].setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
url=encodeURIComponent(url)
var post="url="+url;
xhr[i].node=div;
xhr[i].onreadystatechange=function() {
if(xhr[i].readyState==4)
{
xhr[i].node.innerHTML=xhr[i].responseText;
xhr[i].node.style.display="block";
}
}
xhr[i].send(post);
}
i am not marking it as accepted because i still dont understand why i need to use an array of xhr since a local xhr object should be enough because each time the onreadystate function executes it has the reference of the xhr object. Now since javascript functions are also objects therefore every instance of onreadystate function should have its own reference of xhr object and therefore i shouldnt need to create an array of xhrs.
please correct me if i am wrong here