Javascript addEventListener not working properly - javascript

So i'm having trouble with the event so, normally i try to create an event if we have more than 1 image in the array so i can mouseenter and display another one but currently i don't know why but when we mouseenter the preview (image) it giving the latest result from the array while we still inside the loop ?
var product_type = "";
for(let i = 0; i < this.products_list.length; i++){
var row = this.products_list[i], self = this;
if(row.product_type != product_type){
product_type = row.product_type;
var sub_title = document.createElement("h2"),
separator = document.createElement("hr"),
display_list = document.createElement("ul");
sub_title.id = product_type;
sub_title.innerHTML = localeString.get(product_type);
display_list.id = product_type+"-list";
this.catalog.appendChild(sub_title);
this.catalog.appendChild(separator);
this.catalog.appendChild(display_list);
}
var product = document.createElement("li"),
preview = document.createElement("img"),
container = document.createElement("div");
var array_images = row.product_images.split(",");
preview.src = this.assets+product_type+"/"+array_images[0]+".jpg";
preview.alt = product_type+"#"+row.product_id;
container.appendChild(preview);
product.appendChild(container);
preview.addEventListener("mouseenter", event => {
console.log(array_images);
//here, giving the latest element from the array and not the current selected.
});
display_list.appendChild(product);
}

If your are trying to opt for mouseover event then you should use mouseover in the place of click event. Currently its not working because the event which you called is a click event.

Related

Rendering Info Cards and modal box with forLoop only outs the last result in one of the fields

I am practising vainilla JS and DOM manipulation. I am rendering a group of cards populated with data from an Object (that I fetch from an API, but this happens also if i do it in local).
I get to render the cards,all good, and create a button in each of them, that triggers a Modal box made with Bootstrap, with some additional information about that item.
The problem I have is that when I click on the button, the modal box only displays the information from the last element of the Object.
The function i wrote is as follows :
function createCards(data) {
let cardContainer = document.getElementById('cardContainer');
let modalTitle = document.getElementById('modalTitle');
let modalBody= document.getElementById('modalBody');
for (let i = 0; i < data.length; i++) {
let divCard = document.createElement('div');
divCard.setAttribute('class', 'card');
let imgFish = document.createElement('img');
imgFish.setAttribute('class', 'card-img-top');
let imgUrl = data[i]['Species Illustration Photo'].src
// console.log(imgUrl)
imgFish.setAttribute('src', imgUrl);
let divCardBody = document.createElement('div');
divCardBody.setAttribute('class', 'card-body');
let hCardTitle = document.createElement('h5')
hCardTitle.innerHTML = data[i]['Species Name'];
let pCardText = document.createElement('p');
pCardText.setAttribute('class', 'card-text');
pCardText.innerHTML = 'Kcal = ' + data[i].Calories
let aInfoButton = document.createElement('a');
aInfoButton.setAttribute('class', 'btn btn-primary');
aInfoButton.setAttribute('href', '#');
aInfoButton.setAttribute('data-toggle', 'modal');
aInfoButton.setAttribute('data-target', '#myModal');
aInfoButton.innerHTML = 'Nutrional Info'
cardContainer.appendChild(divCard);
divCard.appendChild(imgFish);
divCard.appendChild(divCardBody);
divCardBody.appendChild(hCardTitle);
divCardBody.appendChild(pCardText);
divCardBody.appendChild(aInfoButton);
//fill in Modal box
aInfoButton.onclick = function () {
createModal(data);
}
}
console.log("createCards() run")
}
and then, the function to populate the modal box :
function createModal(data) {
let modalTitle = document.getElementById('modalTitle');
let modalBody= document.getElementById('modalBody');
for (let i = 0; i < data.length; i++) {
modalTitle.innerHTML = data[i]['Species Name'];
modalBody.innerHTML = data[i]['Cholesterol'];
}
}
I tried also wrapping the creation of those two innerHTML from the modal box inside a different function, thinking it was a problem of time needed to render each item, but it seems that the problem is different, and I can't see which one.
It looks like, at the bottom of your for-loop, you are overwriting the innerHTML every time.
modalTitle.innerHTML = data[i]['Species Name'];
modalBody.innerHTML = data[i]['Cholesterol'];
So when you exit the for loop, what ever iteration of data is last is the one that will be in the modal.
2 ways to go about fixing:
1.) create a modal specific to each card.
2.) add an eventListener to the button that will populate the correct info onclick

passing arguments to an onchange() function

I'm trying to create an image slider, in which moving the handle on the slider will change the image to be displayed.
In the code below, I use an onchange function to dynamically update the image
(id = "image") based on the current value of slider (id = "image-slider-response").
var imageGroup1 = ['imageA.jpg','imageB.jpg','imageC.jpg'];
var slide = document.getElementById('image-slider-response');
var imageDiv = document.getElementById("image");
slide.onchange = function() {
imageDiv.src = imageGroup1[this.value];
}
Now, I'm trying to pass imageGroup as an argument to the onchange function to extend the code above to other image groups.
I followed this link http://www.jstips.co/en/javascript/passing-arguments-to-callback-functions/ but didn't seem to work. Any suggestions to fix this?
var imageGroup1 = ['imageA.jpg','imageB.jpg','imageC.jpg'];
var imageGroup2 = ['imageD.jpg','imageE.jpg','imageF.jpg'];
var slide = document.getElementById('image-slider-response');
var imageDiv = document.getElementById("image");
function myFunction(x){
return function(){
sliderDiv.innerHTML = slide.value;
imageDiv.src = x[slide.value];
}
}
var imageGroup = imageGroup1;
slide.addEventListener("onchange", myFunction(imageGroup));
You're on the right track with the callback there, there's just one thing - when using addEventListener, don't prefix the event with on: just use the plain event name.
slide.addEventListener("change", myFunction(imageGroup));

How to append multiple elements to a div using DocumentFragment

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);
};

How to get the img id for dynamically building IMG tags based on click like Share or Like or Comment

Good Evening Everyone.
Background: I am getting list of images from a Mongo Database and then I am calling ajax once to load those data in to particular div.
Here I am building those img tags dynamically and then appending it to a div.
Now I am trying to get the img id based on user operation, lets say clicks on 'share button' for a particular img, then I have to get the image id, and then have to look search the DB with that image id.
My code after the ajax call is:
function showImages(imageList) {
for ( var i = 0, len = imageList.length; i < len; i++) {
var elem = document.createElement("img");
elem.src = 'getImg/' + imageList[i][0] + '/' + imageList[i][1];
elem.id = imageList[i][2];
alert(elem.id);
elem.height = '100';
elem.width = '100';
elem.alt = 'SPF HYD';
/* $("a[id=shareImage]").click(function(){
var qwerty = $("img", $(this).parent()).attr("id");
alert('image id is after anchor by click...'+qwerty);
}); */
var image = document.getElementById("imageLoad");
image.appendChild(elem);
}
}
Could any one help me to get the image id onclick or any button trigger?
I threw a quick demo together to demonstrate what I meant. It's made possible using jQuery event Delagation
function showImages(imageList) {
for ( var i = 0, len = imageList.length; i < len; i++) {
var elem = document.createElement("img");
elem.src = 'getImg/' + imageList[i][0] + '/' + imageList[i][1];
elem.id = imageList[i][2];
console.log(elem.id);
elem.height = '100';
elem.width = '100';
elem.alt = 'SPF HYD';
var image = document.getElementById("imageLoad");
image.appendChild(elem);
}
}
//The event handler is registered on the document object - the second argument here is the delegate, <img>
$(document).on("click", "img", function(e) {
alert($(this).attr("id"));
});
var imageList = [[0, 1, 2], [3, 4, 5]]; //These values are merely for testing
showImages(imageList);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imageLoad"></div>
Using Event Delegation is necessary here because your img tags are being dynamically generated, plus it's a lot cleaner to register one event handler for all img tags, rather than an event handler for each
Hope this helps
Use addEventListener function to add an Event Listener to your dynamically created element.
var div = document.getElementById("div");
var imgShare = document.createElement("img");
imgShare.src = "http://icons.iconarchive.com/icons/graphicloads/100-flat-2/128/share-2-icon.png";
imgShare.id = "post002";
imgShare.addEventListener("click", share);
div.appendChild(imgShare);
var imgLike = document.createElement("img");
imgLike.src = "http://www.brandsoftheworld.com/sites/default/files/styles/logo-thumbnail/public/102011/like_icon.png?itok=nkurUMlZ";
imgLike.id = "post001";
imgLike.addEventListener("click", like);
div.appendChild(imgLike);
function share(e){
alert("Share id:" + e.currentTarget.id);
}
function like(e){
alert("like id:" + e.currentTarget.id);
}
<div id="div"></div>
JSFiddle Link...

Change zIndex using javascript

It works on the premade divs but on the newly made one, it doesn't work. How do I fix that?
Here's the code on the event for changing the zIndex:
$(".widget").mousedown(function (event) {
var ws = document.getElementById("widget-workspace");
var list = ws.children, x=0;
for(x=0;x<ws.children.length;x++){
console.log(ws.children[x].id);
$("#"+ws.children[x].id).css("zIndex", 99);
}
$(this).css("zIndex", 100);
});
Now, here's the code for adding the div:
document.getElementById("widget-dialog-button").onclick = function () {
var ws = document.getElementById("widget-workspace");
var list = ws.children;
var x, w = document.getElementById("select-widget");
var widget = w.options[w.selectedIndex].value;
var c = document.getElementById("select-widget-color");
var color = c.options[c.selectedIndex].value;
var left = 0, top = 25, docWidth = ws.offsetWidth, check;
for(x=0; x < list.length; x++){
docWidth -= 325;
left += 325;
if(docWidth < 325){
check = false;
docWidth = ws.offsetWidth;
left = 0;
top += 210;
}else{
check = true;
}
}
x-=2;
var iDiv = document.createElement('div');
iDiv.id = 'widget_'+x;
iDiv.className = 'widget';
iDiv.style.backgroundColor = color;
iDiv.style.left = left;
iDiv.style.top = top;
ws.appendChild(iDiv);
$(function() {
$( ".widget" ).draggable();
});
};
If you guys need anything else, feel free to ask.
The answer is quite simple :
"It works on the premade divs but on the newly made one, it doesn't work. How do I fix that?"
It's normal :
$(".widget").mousedown(...);
// should be read as (except that a new var is not created)
var $currentlyExistingWidgets = $(".widget");
$currentlyExistingWidgets.mousedown(...);
To each element of class widget currently existing, you bind an event.
If you want to bind events to elements not existing... You have to reconider your way of thinking and then bind an event listener to a container always existing, with an event delegation mechanism and proper filtering.
For example the following code should catch the event for all .widget, created before or after :
// http://api.jquery.com/on/
$('body').on('mousedown', '.widget', function() { ... });
If you want to search and learn, the key concepts are event bubbling and event delegation.
The way you're attaching the mousedown listener means that only the element that exist at that point will be listened to. Use the on method:
// May want to use something other than body
$('body').on('mousedown', '.widget', function() {
console.log('go');
});
Docs

Categories

Resources