I am retrieving some information from an xml file ( movie information ) and I am creating dynamically some DOM elements according to each movie. I want, when I click on the test element, to get the value of the title of the movie. Right now, no matter which movie I click, it gets the title of the last movie that was introduced.
How can I get the title of each individual movie when I click on that div and not the last one introduced by the for-loop?
xmlDoc=xmlhttp.responseXML;
var x=xmlDoc.getElementsByTagName("movie");
for (i=0;i<x.length;i++)
{
var titlu = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
var description = x[i].getElementsByTagName("description")[0].childNodes[0].nodeValue;
var descriere = document.createElement('div');
descriere.className='expandedDescriere';
descriere.innerHTML = description;
var titlediv = document.createElement('div');
titlediv.className = 'title';
titlediv.id='title';
titlediv.innerHTML = title;
var test=document.createElement('div');
test.className='test';
test.onclick= function(){
var filmName= test.previousSibling.innerHTML;
alert(filmName);
}
placeholder.appendChild(titlediv);
placeholder.appendChild(test);
placeholder.appendChild(descriere);
}
I think your problem might be in the function you assigned to onclick:
test.onclick= function(){
var filmName= test.previousSibling.innerHTML; // <===
alert(filmName);
}
the marked line should be var filmName= this.previousSibling.innerHTML;
My guess is that the var test is hoisted out of the for loop, meaning that when the loop finished, all the onclick function are referencing the same test variable which is the last element you created.
Use this to reference the clicked element:
test.onclick = function() {
var filmName = this.previousSibling.innerHTML;
alert(filmName);
};
Related
I am currently creating a program which utilizes localStorage to create a site with a wishlist like functionality. However when I go to generate the html page that should create the wishlist with the photo of the item, the name and a button to remove said item from the list. But when I go to assign the onClick functionality to the button, the function fires on page load rather then on click. I have four main java script functions, one to add to the localstorage, one to remove from local storage, a helper function for removing and the one that will generate the wishlist page (where the problem is).
function genWishListPage(){
for (var i = 0; i < localStorage.length; i++) {
var item = getWishlist(i);
var name = document.createElement("p");
var removeButton = document.createElement("button");
var image = document.createElement("img")
image.src = item.image;
removeButton.innerText = "Remove from wishlist";
removeButton.onClick = RemoveFromWishList(item.name);
removeButton.setAttribute("ID","remove");
name.innerText = item.name;
document.body.appendChild(image);
document.body.appendChild(name);
document.body.appendChild(removeButton);
document.body.appendChild(document.createElement("BR"));
//removeButton.setAttribute("onclick", RemoveFromWishList(item.name));
//removeButton.addEventListener('click', RemoveFromWishList(item.name));
//document.getElementById("remove").addEventListener("click",RemoveFromWishList(item.name));
}
}
The commented parts are ways I have already tried and gotten the same bug.
Any help or advice is appreciated.
When you write
removeButton.onClick = RemoveFromWishList(item.name); you are assigning the return value of the function call to the onClick event. Instead you can write
removeButton.onClick = function() { RemoveFromWishList(item.name);}
You should assign a function to the onClick event listener.
function JGallery() {
this.elements = this._init();
this.overlay = this.elements.overlay;
this.media_hld = this.elements.media_hld;
}
JGallery.prototype._init = function(){
var overlay = document.createElement('div');
var media_hld = document.createElement('div');
return{
'overlay': overlay,
'media_hld': media_hld
}
};
This is where I create a document fragment and using it so I can add several div to same element:
JGallery.prototype.getReference = function(holder) {
var overlay = this.overlay;
var media_hld = this.media_hld;
var that = this;
var holderChildren = holder.querySelectorAll('img');
var docfrag = document.createDocumentFragment();
holderChildren.forEach(function (e) {
e.addEventListener('click', JGallery.prototype.showMe.bind(that), false);
var media_holder = that.media_hld;
media_holder.textContent = "<img src="+e.getAttribute('src')+">";
docfrag.appendChild(media_holder);
//it only appends the last child of my array...
});
overlay.appendChild(docfrag);
};
my goal is to have something like this:
<div class="JGallery_BG">
<div class="JGallery_mediaContainer"><img src="images/thumb_video.jpg"></div>
<div class="JGallery_mediaContainer"><img src="images/thumb_video.jpg"></div>
</div>
by the way the forEach function works well, 8 or 9 times. But I'm not sure whether it adds node to docFrag on every run or not.
Another thing, I'm not insisting to use a document fragment, if there is a better way to add multiple elements to one element, I like to know about it and use it.
One of the problems is that you are constantly re-using the same media holder <div> element in every iterations.
In the code below that.media_hld is always referencing the same element.
var media_holder = that.media_hld;
media_holder.textContent = "<img src="+e.getAttribute('src')+">";
docfrag.appendChild(media_holder);
If you clone the node it should work and you also need to set the innerHTML property, not the textContent.
var media_holder = that.media_hld.cloneNode();
One other thing I did spot is that what's returned from querySelectorAll is not an array and thus doesn't have a forEach method.
You could borrow forEach from an array instance though:
[].forEach.call(holderChildren, forEachBodyFunction);
The entire thing could read:
JGallery.prototype.getReference = function(holder) {
var docfrag = document.createDocumentFragment(),
images = holder.querySelectorAll('img');
[].forEach.call(images, function (img) {
img.addEventListener('click', JGallery.prototype.showMe.bind(this), false);
var media_holder = this.media_hld.cloneNode();
media_holder.appendChild(img.cloneNode());
docfrag.appendChild(media_holder);
}.bind(this));
this.overlay.appendChild(docfrag);
};
I have been practicing my Vanilla Js/jQuery skills today by throwing together a newsfeed app using the news-api.
I have included a link to a jsfiddle of my code here. However, I have removed my API key.
On first load of the page, when the user clicks on an image for a media outlet, e.g. 'techcrunch', using an addEventListener, I pass the image's id attribute to the API end point 'https://newsapi.org/v1/articles' and run a GET request which then proceeds to create div elements with the news articles content.
However, after clicking 1 image, I cannot get the content to reload unless I reload the whole page manually or with location.reload().
On clicking another image the new GET request is running and returning results, as I am console logging the results.
I am looking for some general guidance on how to get the page content to reload with each new GET request.
Any help would be greatly appreciated.
Many thanks for your time.
Api convention:
e.g https://newsapi.org/v1/articles?source=techcrunch&apiKey=APIKEYHERE
EventListener:
sourceIMG.addEventListener('click', function() {
$.get('https://newsapi.org/v1/articles?source=' + this.id + '&sortBy=latest&apiKey=APIKEYHERE', function(data, status) {
console.log(data);
latestArticles = data.articles;
for (i = 0; i < latestArticles.length; i++) {
//New Article
var newArticle = document.createElement("DIV");
newArticle.id = "article";
newArticle.className += "article";
//Title
//Create an h1 Element
var header = document.createElement("H1");
//Create the text entry for the H1
var title = document.createTextNode(latestArticles[i].title);
//Append the text to the h1 Element
header.appendChild(title);
//Append the h1 element to the Div 'article'
newArticle.appendChild(header);
//Author
var para = document.createElement("P");
var author = document.createTextNode(latestArticles[i].author);
para.appendChild(author);
newArticle.appendChild(para);
//Description
var description = document.createElement("H4");
var desc = document.createTextNode(latestArticles[i].description);
description.appendChild(desc);
newArticle.appendChild(description);
//Image
var image = document.createElement("IMG");
image.src = latestArticles[i].urlToImage;
image.className += "articleImg";
newArticle.appendChild(image);
//Url link
//Create a href element
var a = document.createElement('a');
var link = document.createElement('p');
var innerLink = document.createTextNode('Read the full story ');
link.appendChild(innerLink);
a.setAttribute("href", latestArticles[i].url);
a.innerHTML = "here.";
link.appendChild(a);
newArticle.appendChild(link);
//Append the Div 'article' to the outer div 'articles'
document.getElementById("articles").appendChild(newArticle);
}
});
}, false);
I tried your fiddle using an api key. It is working for me in that content new content is appended to the previous content in the #articles div. If I'm understanding your question, when a news service image is clicked you would like for only that news service's articles to show. To do that you would need to clear the contents of #articles before appending new content.
To do that with plain js you could use the following above your for loop:
// Removing all children from an element
var articlesDiv = document.getElementById("articles");
while (articlesDiv.firstChild) {
articlesDiv.removeChild(articlesDiv.firstChild);
}
for (i = 0; i < latestArticles.length; i++) {...
Full disclosure, I added the variable name 'articlesDiv' but otherwise the above snippet came from https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild
I am creating html page which needs to create a list of links dynamically on a click of button. I know how to create this list when number of links to be created is known before like this:
//For 4 tags:
var mydiv = document.getElementById("myDiv");
var aTag = document.createElement('a');
aTag.innerHTML = "link1 text";
aTag.setAttribute('onclick',"func()");
mydiv.appendChild(aTag);
var bTag = document.createElement('b');
bTag.innerHTML = "link2 text";
bTag.setAttribute('onclick',"func()");
mydiv.appendChild(bTag);
var cTag = document.createElement('c');
cTag.innerHTML = "link3 text";
cTag.setAttribute('onclick',"func()");
mydiv.appendChild(cTag);
var dTag = document.createElement('d');
dTag.setAttribute('onclick',"func()");
dTag.innerHTML = "link4 text";
mydiv.appendChild(dTag);
But the problem is that the count will be known at run time and also on function call i need to identify the id of link that invoked function.. Can anybody help?
I don't know weather you receive or not the HTML to be shown in the anchor, but anyway, this should do the work:
function createAnchor(id, somethingElse) {
var anchor = document.createElement('a');
anchor.innerHTML = "link" + id + " text";
anchor.setAttribute("onclick", "func()");
return anchor;
}
Then you call the function like this:
function main(num_anchors) {
var mydiv = document.getElementById("myDiv");
for (var i = 0; i < num_anchors; i += 1) {
mydiv.appendChild(createAnchor(i));
}
}
Of course this code can be improved, but this is just for show how can this be possible.
Yes it is possible to do this at runtime .
JQuery provides very useful dom manipulation . So you can traverse the dom , filter what you need ..
you can find a lot of useful functions here .
http://api.jquery.com/category/traversing/
It would look something like this.
$( document ).ready(function() {
$( "a" ).each(function( index ) {
// enter code here..
}
});
document.ready gets invoked once the DOM has loaded.
I have a link that is attached with an "onclick" function. When pressed it attaches an img element into a separate div called "mediaBox". The problem I'm having is that if it's pressed multiple times then it attaches more instances of the img. How can I control this. I'm still new to JavaScript and I prefer to receive this answer in pure Javascript not jQuery, as I will cross that bridge after I have a full understanding of Javascript.
var rkf = document.getElementById("submenulinks").getElementsByTagName("li")[0];
rkf.onclick = function(){
var client = document.getElementById('client');
var description2 = document.getElementById('description2');
var role = document.getElementById('role');
var mediaBox = document.getElementById('mediaBox');
var thumb = document.getElementById("thumb");
var client2 = document.getElementById("client2");
var newImage = document.createElement("img");
client2.innerHTML = "Role - Applications";
client.innerHTML = "RKF Real Estate";
client2.innerHTML = "Role - Applications";
description2.innerHTML = "Quarterly Catalog of Exclusive Listings managed by RKF";
role.innerHTML = "Custom designed Cover and listings content. Tables were also utilized within Indesign. <br><br><b><i> Photoshop and Indesign</i></b>";
newImage.setAttribute("src", "../images/rkf_cover.jpg");
newImage.setAttribute("height", "500px");
newImage.setAttribute("width", "387px");
newImage.setAttribute("alt", "rkf");
newImage.setAttribute("href", "#");
mediaBox.style.backgroundImage = "none";
document.getElementById("mediaBox").appendChild(newImage);
newImage.style.display = "block";
newImage.style.marginLeft = "auto";
newImage.style.marginRight = "auto";
newImage.style.marginTop = "25px";
}
rkf.onclick = function(){
var client = document.getElementById('client');
...
...
...
// Remove the handler after it ran once.
this.onclick = null; // <<<<<========================
}
Since you do want to use jQuery in the future, it's equal to:
$('#submenulinks li:first').one('click', handler);