Increasement number not rising in for loop - javascript

I am trying to figure this out. I have 3 buttons id (test1, test2, test3) in my HTML! In my jQuery I have an click function in a for loop like this:
$(document).ready(function() {
for (var i = 0; i < 3; i++) {
$("#test"+i).on('click', function() {
alert("I am clicked! ("+i+")");
});
}
});
Now, I am alerting a message for each of them, nut all the (i) in the alert is giving the last number "3"... How do i get it to write "I am clicked (1)" if I press test1 and equally if I press test2 and test3?
I have a jsfiddle to explain here.
Hoping for help and thanks in advance ;-)

The problem is that the handlers you're assigning have an enduring reference to the i variable, not a copy of that variable as of when the function was created. They're closures over the i variable (and other things). More: Closures are not complicated
There are several ways to solve this.
You can put a piece of information on the elements so they can all share a single handler, which is probably preferred. (You actually already have that information in your example, we can figure out i from the elements' id values, but I'm assuming in the real world things are more complex.)
$(document).ready(function() {
for (var i = 0; i < 3; i++) {
$("#test"+i).attr("data-index", i).click(clickHandler);
}
function clickHandler() {
alert("I am clicked! ("+this.getAttribute("data-index")+")");
// Or:
alert("I am clicked! ("+$(this).attr("data-index")+")");
}
});
Updated Fiddle
Note how we have just one handler function, and it handles clicks on all of the elements.
Using a single handler may also mean you can take advantage of event delegation, hooking the click on an ancestor element rather than on each of these individual elements, e.g.:
$("selector for ancestor").on("click", "[id^=test]", ...);
Updated Fiddle
You can use a builder function to create the click handlers so that they close over something that doesn't change (an argument we pass to the builder):
$(document).ready(function() {
for (var i = 0; i < 3; i++) {
$("#test"+i).on('click', buildHandler(i));
}
function buildHandler(index) {
return function() {
alert("I am clicked! ("+index+")");
};
}
});
Updated Fiddle

Try something like this
$(document).ready(function() {
for (var i = 0; i < 3; i++) {
$("#test"+i).on('click', function() {
var value = $(this).attr('id');
value=value.replace("test", "");
value=parseInt(value)+1;
alert("I am clicked! ("+value+")");
});
}
});

Related

Change Click Function to hover (Vanilla Javascript)

I am using this code:
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById("div#logo1").onclick = function(){
hideAllImages();
document.getElementById("01").style.display="block";
removeNavHighlight();
document.getElementById("div#logo1").classList.add("my_active");
};
document.getElementById("div#logo2").onclick = function(){
hideAllImages();
document.getElementById("02").style.display="block";
removeNavHighlight();
document.getElementById("div#logo2").classList.add("my_active");
};
document.getElementById("div#logo3").onclick = function(){
hideAllImages();
document.getElementById("03").style.display="block";
removeNavHighlight();
document.getElementById("div#logo3").classList.add("my_active");
};
function hideAllImages() {
var items = document.getElementsByClassName('changing_text');
var itemsLen = items.length;
for(var i = 0; i < itemsLen; i++) {
items[i].style.display="none";
}
}});
Which working fine with click event but I want to convert it to be functional when I hover to the element.
What this function must to: for example, when I hover on an image other element must appear and previous element must become hidden.
This is Vanilla Javascript code.
Any suggestions? tried to change .onclick to .onmouseover but not working.
It's not .mouseover it's .onmouseover
Is it working for you to replace .onclick by .onmouseover?
These functions are always in format on<event>. It should be .onmouseover as the other answers have already said. Note that you'd be using mouseover if you were adding an event listener using the addEventListener function.

How to generate dynamically events in jquery?

I'm trying to set event attributes on a group of drop-down generated dynamically but for some reason the events aren't working.
Heres's my code.
$(document).ready(function () {
var idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").attr("onchange", generatePrice);
}
});
var generatePrice = function () {
alert(this.value().toString());
}
I think this must work for you
$(document).ready(function () {
var idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").on("change", generatePrice);
}
});
var generatePrice = function () {
alert($(this).val());
}
And have a look at this:
How to use the jQuery Selector in this web application?
HTML:
<select class="dynamicSelects">
....
</select>
JS:
var generatePrice = function () {
alert(this.value);
};
$(document).ready(function () {
$('body').on('change', '.dynamicSelects', generatePrice);
});
This is an example of using the on method provided by jQuery and delegating the events. This means that even if those drop downs are not in the DOM yet you can still attach the event to it and whenever they exist in the DOM the event will fire. It basically says attach these events to body but fire on elements with the class dynamicSelects. This covers adding any other dynamically generated drop downs with this class later as well.
Setting attributes to attach events, while it may work, should really be done using the on method or in plain JS the addEventListener, in my opinion.
Also when operating on plain DOM elements the value property is not a function so no value() is needed. Just this.value. And you don't need to convert it to a string because value returns a string. If it were a jquery object then you can do $(this).val() which is a function.
I only suggest this change of course because if you are going to use a library like jQuery at least take advantage of the things it offers.
Did you search into the jQuery documentation?
$(document).ready(function () {
var $idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").attr("onchange", generatePrice);
}
$( "#idRoomTypesList" ).change(generatePrice());
});
var generatePrice = function () {
alert(this.value().toString());
}

Javascript onclick for class and name

I'm new to JavaScript and am unsure how to do the following:
I've got two links with the same css "class" but different "name" attributes. I need to perform different functions to each one individually when clicked using unobtrusive Javascript. Is there anyway to do this?
Example code:
<a class="ClassName" name="link1">Link 1</a>
<a class="ClassName" name="link2">Link 2</a>
Lets say I need to output "This is link 1" to the console when I click link 1. And "this is link 2" when Link 2 is clicked.
Attach an event handler to the elements, and just check the name and do whatever you'd like
var elems = document.querySelectorAll('.ClassName');
for (var i=elems.length; i--;) {
elems[i].addEventListener('click', fn, false);
}
function fn() {
if ( this.name == 'link1' ) {
console.log('This is link1');
} else if ( this.name == 'link2' ) {
console.log('This is link2');
}
}
FIDDLE
You can do like in this JS Fiddle Demo , its pretty simple:
JS:
var anchorTags = document.querySelectorAll('.ClassName');
for (var i = 0; i < anchorTags.length; i++) {
anchorTags[i].onclick = function() {
alert(this.innerHTML);
}
}
Hope this helps.
It's not very performant but you can use name selectors. .className[name=link1] however, if you have multiple links the best way to handle something like this is to use event delegation. It's really easy if you have access to jquery
I would do something like
parent.on('click', '.ClassName', function(event) {
var button = $(this),
name = button.attr(name);
switch(name):
case link1
case link2
...
});
this way you don't have to assign individual events to the different links. You could also do something like this without event delegation if you really wanted to it would just be changing it to
var links = $('.ClassName');
links.on('click', function() {
...
});
Keep in mind that the latter will attach an eventHandler to each link.
If you don't have jQuery you can still do this you just need to grab the elements differently and handle attachEvent vs addEventHandler. Also, applying the delegation will require delving into the event.currentTarget object.
something like:
var parent = document.getElementById('parentid');
parent.addEventListener('click', function(event) {
if (event.currentTarget.getAttribute('class')indexOf('ClassName') > -1) {
... do stuff w/ that link here
}
});

pass through current target name to function

I'd like to dynamically create event listeners for multiple buttons, and subsequently, show a particular frame label depending on the button clicked, but I'm unsure what to pass through (FYI, this is will be used for HTML5 canvas in Flash CC, but principally the same should apply to a web page for showing divs etc). I currently have this:
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
selfHome["btn" + i].addEventListener('click', openPop);
}
}
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
createListeners();
It creates the listeners fine, but I don't really know where to start with passing through the current button instance name to tell it which frame label to gotoAndPlay.
Based on the code that you have, I'd simply change the .addEventListener() to call a generic function (rather than openPop, directly), and pass it the reference to the button. So, this:
selfHome["btn" + i].addEventListener('click', openPop);
. . . would become this:
selfHome["btn" + i].addEventListener('click', function() {
openPop(this);
});
At that point, you would then have to update openPop to accept a parameter for the reference to the element that triggered it . . . something like:
function openPop (currentButton) {
At that point, you could reference the clicked button, by using currentButton in the openPop logic.
I'm not sure I totally understand your question. However if you just need to pass the button instance (in you case "selfHome["btn" + i]") you could call an anonymous function in your event handler which calls openPop() with the button instance as an arugment. Would this work for you?
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
var currentBtn = selfHome["btn" + i];
currentBtn.addEventListener('click', function(){openPop(currentBtn);} );
}
}
function openPop (btn) {
alert("test");
selfHome.gotoAndPlay(/*use button instance 'btn' to find frame*/);
}
createListeners();
When the event is triggered the this keyword inside the handler function is set to the element is firing the event EventTarget.addEventListener on MDN. If the button have the data needed to be retrieved just get it from the this keyword:
function openPop (btn) {
alert(this.name);
/* ... */
}
It looks like you expect it to contain the function gotoAndPlay() as well as the btn elements (which contain both an ID (of btn[number]) and a name with something special at substr(3) (I assume the same as the id). If those things were all true, it should work in chrome... in other browsers you'll need to add event to the openPop() method signature.
function openPop (event) {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
I believe this is what you are looking for and adding that one word should fix your problem (assuming some things about your dom and what selfHome contains):
JSFiddle
You could also leave out the event from openPop() and replace event.currentTarget with this:
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+this.name.substr(3));
}
JSFiddle

JQuery Bind click event to appended element with an argument

I'm trying to populate a ul list with some li elements and give each li element a link that calls the same function with a different argument. However it doesn't seem to work, i've attached the code below, CheckForNewMail is called on document load. Can anyone please help me out?
function CheckForNewMail() {
//////////////////////////////////////////////////////////////////
// This will be dynamic
MailInInbox[0] = new Array("0", "Mail One");
MailInInbox[1] = new Array("12", "Mail Two");
MailInInbox[2] = new Array("32", "Mail Three");
MailInInbox[3] = new Array("5", "Mail Four");
//////////////////////////////////////////////////////////////////////
$('#mail-in-inbox').children().remove();
size = 4; element = $('#mail-in-inbox');
for(i = 0; i < size; ++i) {
var link = $(''+ MailInInbox[i][1] +'');
link.live('click', function() {
LoadMailById(i);
});
li = $('<li></li>');
li.append(link);
element.append(li);
}
}
function LoadMailById(id) {
alert("Button "+ id +" clicked!");
}
First, I'm making an assumption here:
That you want the id of the email in that click function, not the index e.g. 0, 12, 32, 5, rather than 0, 1, 2, 3.
Given that (easy to adjust with .index() if the assumption is incorrect), you can do this:
function CheckForNewMail() {
MailInInbox[0] = ["0", "Mail One"];
MailInInbox[1] = ["12", "Mail Two"];
MailInInbox[2] = ["32", "Mail Three"];
MailInInbox[3] = ["5", "Mail Four"];
$('#mail-in-inbox').empty();
var size = 4, element = $('#mail-in-inbox');
for(i = 0; i < size; ++i) {
$(''+ MailInInbox[i][1] +'')
.data('id', MailInInbox[i][0]).wrap('<li/>').parent().appendTo(element);
}
}
There are a few changes here:
Array literals, much simpler notation
Proper var declaration on variables (if they aren't already defined elsewhere)
Using .data() to store the id on the <a> we just created
Then, using that stored data, we can attach a single handler to the #mail-in-inbox container one time (on DOM ready), rather than one to each <a> each time this function runs, it should look like this:
$('#mail-in-inbox').delegate('.inbox-link', 'click', function() {
alert("Button "+ $.data(this, 'id') +" clicked!");
});
This would display "Button 0 clicked!", "Button 12 clicked", etc. You can test out all of the above in a demo here.
One problem is that the variable i will always be that of the last link because by the time the user clicks any link, the loop would have completed. One way to fix this would be to use the .data() method to associate a piece of information with each li element:
link.data('mailId', i); // within the loop
Then you can bind a single event handler for all inbox links inside #mail-in-inbox:
$('#mail-in-inbox').on('click', '.inbox-link', function() {
LoadMailById($(this).data('mailId'));
});
Edited to add: .on() was introduced in jQuery 1.7. If you are using jQuery 1.6 or older, use .delegate() or .live() (as in the question and the original version of this answer) instead.
There are a couple issues.
First, that's not how you use .live(). The .live() method is called against a jQuery object that was given a selector. You can do it at any point (even before the DOM loads), and any clicks on the page that match the selector will fire the handler.
In your case, it would go something like:
$('.inbox-link').live('click',function() {
// whatever
});
In your case, where you're assign a separate handler to each item, you would use .bind instead of live().
As another user mentioned, you'll not have the correct value of i in the handler though. You can use $.each() to overcome this.
$.each(MailInInbox, function( i ) {
var link = $(''+ MailInInbox[i][1] +'');
link.bind('click', function() {
LoadMailById(i);
});
$('<li></li>').append( link ).appendTo( element );
});
Now you'll have the correct value of i in the handler for each link.
LoadMailById(i);
i is a reference here and increased on each for-iteration. Thus, after the for loop it holds the value of size; 4.
link.live('click', (function(index) {
return function() {
LoadMailById(index);
};
)(i);
});
I think this should work to fix the problem. The anonymous function takes your argument i and binds it to the variable index so that when the click even occurs, it's not using the value i leftover from the end of the loop but is instead using it's value at the time of the binding.

Categories