Adding mouseover event to a javascript created DIV - javascript

Im currently getting data from Google places and am dynamically creating the div to display the results. I am trying to add a mouseover event to each div yet am having no luck implementing it. Ive check the html source and it seems to not add the event for any of the created DIV's.
JS:
for (var i = 0; i < relatedProperties.length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.className = "item_holder";
div.onmouseover = PanToMarker(relatedProperties[i].formatted_address);
document.getElementById('relatedpropertyDIV').appendChild(div);
}
function PanToMarker(address) {
//Grabs the address and pans to it on the map.
}

I would imagine you need to wrap your onmouseover function like this:
div.onmouseover = function() {
PanToMarker(relatedProperties[i].formatted_address);
};
This is because when you click on the element, the onmouseover function gets called with no arguments. When you specify arguments to PanToMarker like in your question, instead of assigning the function as may be intuitive, instead it executes the function then and there, and then assigns the function's output. Wrapping the function like this assures that the function doesn't get called instead while you're trying to assign it.

When you add the onmouseover event handler in this manner, you will not see it in the dom.
I would recommend that you store the index as a data property in the DOM. Then you will be able to access it from the mouseover method ...
for (var i = 0; i < relatedProperties.length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.setAttribute('data-index', i);
div.className = "item_holder";
div.onmouseover = PanToMarker;
document.getElementById('relatedpropertyDIV').appendChild(div);
}
function PanToMarker() {
var selectedIndex = this.getAttribute('data-index');
map.panTo(relatedProperties[selectedIndex].geometry.location);
}
There may be performance implications since you will be appending i elements to the DOM, each of which may cause a re-draw. It might be better to create all the elements first, then append once.
var section = document.createElement('section');
for (var i = 0, length = relatedProperties.length; i < length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.setAttribute('data-index', i);
div.className = "item_holder";
div.onmouseover = PanToMarker;
section.appendChild(div);
}
document.getElementById('relatedpropertyDIV').appendChild(section);
function PanToMarker() {
var selectedIndex = this.getAttribute('data-index');
map.panTo(relatedProperties[selectedIndex].geometry.location);
}

Related

Do I need a parameter in this function?

In this homework assignment, I'm having issues with this part of the problem.
window.onload=setup;
function setup()
{
var questions = document.querySelectorAll('ol li');
for (var i= 0; i < questions.length ; i++)
{
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish()
{
var phraseNumber = parseInt(question[i].id)
document.getElementById(phraseNumber).innerHTML = english[phraseNumber];
english[phraseNumber].style.font = "italic";
english[phraseNumber].style.Color = "rgb(191,22,31)";
}
a) Using the id property of the list item experiencing the mousedown event, extract the index number with the the parseInt() function and store that value in the phraseNumber variable.
I get an error, saying questions is not defined in the showenglish().
Am I supposed to be referencing another object?
You need to pass the question as a parameter:
for(i=0;i<question.length;i++){
let a=i;//important for scoping
question[a].onmousedown=function(){
showEnglish(question[a]);
}
}
function showEnglish(question){
document.getElementById(question.id).style.font="italic";
...
}
(Note: this answer contains ES6. Do not use it in real productional environment. The let a=i; defines that a is kept for being used inside of the listener, while i will always be question.length, because the event is probably clicked after the loop occured...)
Alternatively, the event listener binds this as the clicked element:
question[i].addEventListener("click",showEnglish,false);
function showEnglish(){
document.getElementById(this.id).style.font="italic";
...
}
The mousedown event is raised when the user presses the mouse button. Look at the documentation for the mousedown event.
Your event handler function will be passed an Event object, which has a target property, which is a reference to the element that the mouse clicked on.
You can access this inside your event handler function with event.target.
window.onload = setup;
function setup() {
var questions = document.querySelectorAll('ol li');
for (var i = 0; i < questions.length; i++) {
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish(event) {
var phraseNumber = parseInt(event.target.id);
// etc
};

How to Autorun an onclick event

sorry am still learning JavaScript, read W3Cschools javascript and Jquery but there is a lot they don't teach.
I am studying animation at the moment, how do I auto start this rather then wait for someone to click (event listener), I've attempted turning it into a function but I must be doing it wrong, also 1 more what does (Idx) mean, I understand (id) is Html ID element but not sure Idx, not easy to find on google. to read, event listener starts at 5th line from the bottom, and the shuffle cards is 6th line from top (not sure if that helps), original code is located here http://www.the-art-of-web.com/javascript/css-animation/ thanks for any help.
Regards. William.
var cardClick = function(id)
{
if(started) {
showCard(id);
} else {
// shuffle and deal cards
card_value.sort(function() { return Math.round(Math.random()) - 0.5; });
for(i=0; i < 16; i++) {
(function(idx) {
setTimeout(function() { moveToPlace(idx); }, idx * 100);
})(i);
}
started = true;
}
};
// initialise
var stage = document.getElementById(targetId);
var felt = document.createElement("div");
felt.id = "felt";
stage.appendChild(felt);
// template for card
var card = document.createElement("div");
card.innerHTML = "<img src=\"/images/cards/back.png\">";
for(var i=0; i < 16; i++) {
var newCard = card.cloneNode(true);
newCard.fromtop = 15 + 120 * Math.floor(i/4);
newCard.fromleft = 70 + 100 * (i%4);
(function(idx) {
newCard.addEventListener("click", function() { cardClick(idx); }, false);
})(i);
felt.appendChild(newCard);
cards.push(newCard);
I've gone through your code and added comments to try and help explain what is going on in this file:
//Declare card click function. Takes one parameter (id)
var cardClick = function(id){
if(started) {
showCard(id);
} else {
// shuffle and deal cards
card_value.sort(function() {
return Math.round(Math.random()) - 0.5;
});
for(i=0; i < 16; i++) {
(function(idx) {
setTimeout(function() {
moveToPlace(idx);
}, idx * 100);
})(i);
}
started = true;
}
};
// initialise
//set stage as reference to some element
var stage = document.getElementById(targetId);
//append a div with ID "felt" to the stage element
var felt = document.createElement("div");
felt.id = "felt";
stage.appendChild(felt);
// template for card
//declare card variable as a div with some html content
var card = document.createElement("div");
card.innerHTML = "<img src=\"/images/cards/back.png\">";
//Loop from 0 to 16, where i = current value
for(var i=0; i < 16; i++) {
//create a copy of the card made earlier
var newCard = card.cloneNode(true);
//apply some attributes to the new card
newCard.fromtop = 15 + 120 * Math.floor(i/4);
newCard.fromleft = 70 + 100 * (i%4);
//Create and run an anonymous function.
//The function takes one parameter (idx)
//The function is called using (i) as (idx)
(function(idx) {
//add click handler to the card element that triggers the card click
//function with parameter (idx)
newCard.addEventListener("click", function() { cardClick(idx); }, false);
})(i);
//add new card to the stage
felt.appendChild(newCard);
//add new card to an array of cards
cards.push(newCard);
} //end for loop (I added this. It should be here)
how do I auto start this rather then wait for someone to click
The way I would do it, is add a manual click event after the for loop that targets the first card that has the event handler. Because there is no ID set on the cards, I would try using the array that the cards are added to. Assuming that the cards array was empty when we started:
cards[0].click();
If that doesn't work, I would try targeting the item in the DOM. We know that each card is added to the end of div#felt. So, if we can target the first div inside felt, we should be able to trigger the click event on it.
document.getElementByID("felt").firstChild.click();
what does (Idx) mean
I'm hoping the comments help explain this. It looks like the variable idx is just used as an extended reference of i. Inside a for loop, the writer creates a function that takes one parameter (idx). The for loop has a variable (i) that increases by one for each instance of the loop. Each time the loop happens, i is passed into function as idx.
I hope that helps to get you an understanding of how this code works.

parentNode becomes null after removing previous child element

So, I'm trying to have a button add another dropdown (DD in my code) to the page, and it works just dandy, except when I try to remove (which "works") the remaining node no longer has the parentNode set properly.
Here is my code:
function insertAfter(newNode, elem) {
elem.parentNode.insertBefore(newNode, elem.nextSibling);
}
function addSwitchMenu() {
var lastDD = dropdowns.switches.last();
var newDD = lastDD.cloneNode();
newDD.innerHTML = lastDD.innerHTML;
var oldButton = document.getElementById("add-switch");
var newButton = oldButton.cloneNode();
var newBR = document.createElement("br");
oldButton.value = '-';
oldButton.id = 'remove-switch';
oldButton.onclick = function() {
var index = dropdowns.switches.indexOf(newDD);
dropdowns.switches.splice(index,1);
lastDD.parentNode.removeChild(lastDD);
oldButton.parentNode.removeChild(oldButton);
newBR.parentNode.removeChild(newBR);
updateResults();
}
dropdowns.switches.push(newDD);
console.log(newDD);
console.log(lastDD.parentNode);
insertAfter(newDD, lastDD);
insertAfter(newButton, lastDD);
insertAfter(newBR, lastDD);
}
And basically I call this function, then I call the remove function of the first one, then I call this function once more using the node that was created with the first one. I'm guessing it's something to do with the referencing node being removed, but the new node has a parentNode up until the other node is removed. Why? And how can I fix this?

Loading and removing images with DOM, Javascript

I'm new to DOM and I'm having trouble removing multiple images that I loaded
this loads 7 images (1.jpg, 2.jpg, etc..)
function loadImages() {
for (var i = 1; i < 8; i++ ) {
var img = document.createElement("img");
img.src = "images/"+i+".jpg";
var idName = "img"+i+"";
document.getElementById(idName).appendChild(img);
}
}
this should remove all of them, but doesn't.. I think it breaks at the removeChild line.
function removeImages() {
for (var i = 1; i < 8; i++ ) {
var idName = "img"+i+"";
var d = document.getElementById(idName);
d.removeChild(document.getElementById(img));
}
}
I think I'm doing something fundamentally wrong, because I don't fully understand how this works...
In the removeImages function the variable img is not initialized. And even if it was you don't set the id for any of the images in the loadImages function. You could modify your code like this:
function loadImages() {
for (var i = 1; i < 8; i++ ) {
var img = document.createElement("img");
img.src = "images/"+i+".jpg";
img.id = i;
var idName = "img"+i+"";
document.getElementById(idName).appendChild(img);
}
}
function removeImages() {
for (var i = 1; i < 8; i++ ) {
var d = document.getElementById(i);
d.parentNode.removeChild(d);
}
}
Your code example implies that you're trying to remove a child element of the image and not the image itself. Also, you're using the wrong variable to reference the image. Maybe it works when you replace this line:
d.removeChild(document.getElementById(img));
With this:
d.parent.removeChild(document.getElementById(idName));
Also, if you're not that familiar with the DOM tree, you might want to take a look at jQuery, which is more browser-independent than regular DOM instructions.
If you are doing DOM manipulation, I would recommend that you use jQuery (or at least try it out).
It will make your life more pleasant, you will be a happier person and it will prevent you from committing harakiri.

JavaScript closures and variable scope

I am having trouble with JS closures:
// arg: an array of strings. each string is a mentioned user.
// fills in the list of mentioned users. Click on a mentioned user's name causes the page to load that user's info.
function fillInMentioned(mentions) {
var mentionList = document.getElementById("mention-list");
mentionList.innerHTML = "";
for (var i = 0; i < mentions.length; i++) {
var newAnchor = document.createElement("a");
// cause the page to load info for this screen name
newAnchor.onclick = function () { loadUsernameInfo(mentions[i]) };
// give this anchor the necessary content
newAnchor.innerHTML = mentions[i];
var newListItem = document.createElement("li");
newListItem.appendChild(newAnchor);
mentionList.appendChild(newListItem);
}
document.getElementById("mentions").setAttribute("class", ""); // unhide. hacky hack hack.
}
Unfortunately, clicking on one of these anchor tags results in a call like this:
loadUserNameInfo(undefined);
Why is this? My goal is an anchor like this:
<a onclick="loadUserNameInfo(someguy)">someguy</a>
How can I produce this?
Update This works:
newAnchor.onclick = function () { loadUsernameInfo(this.innerHTML) };
newAnchor.innerHTML = mentions[i];
The "i" reference inside the closure for the onclick handlers is trapping a live reference to "i". It gets updated for every loop, which affects all the closures created so far as well. When your while loop ends, "i" is just past the end of the mentions array, so mentions[i] == undefined for all of them.
Do this:
newAnchor.onclick = (function(idx) {
return function () { loadUsernameInfo(mentions[idx]) };
})(i);
to force the "i" to lock into a value idx inside the closure.
Your iterator i is stored as a reference, not as a value and so, as it is changed outside the closure, all the references to it are changing.
try this
function fillInMentioned(mentions) {
var mentionList = document.getElementById("mention-list");
mentionList.innerHTML = "";
for (var i = 0; i < mentions.length; i++) {
var newAnchor = document.createElement("a");
// Set the index as a property of the object
newAnchor.idx = i;
newAnchor.onclick = function () {
// Now use the property of the current object
loadUsernameInfo(mentions[this.idx])
};
// give this anchor the necessary content
newAnchor.innerHTML = mentions[i];
var newListItem = document.createElement("li");
newListItem.appendChild(newAnchor);
mentionList.appendChild(newListItem);
}
document.getElementById("mentions").setAttribute("class", "");
}

Categories