Initialize onchange event inside a loop - Javascript - javascript

I'm trying to bind an onChange event to 7 dropdowns inside a loop. But when any of dropdown changes, the onChange event for the last one is always executed.
$(function () {
for (var i = 1; i <= 7; i++) {
$('select[id$="bodysys' + i + '"]').change(function () {
if (this.value == "99")
enabletextbox($('input[id$="bodysys' + i + 'spec"]')[0]);
});
}
}
How to make onChange work for all elements separately?

This is called the last one only problem, and is solved using a closure:
$(function () {
for (var i = 1; i <= 7; i++) {
(function (i) {
$('select[id$="bodysys' + i + '"]').change(function () {
if (this.value == "99")
enabletextbox($('input[id$="bodysys' + i + 'spec"]')[0]);
});
})(i);
}
}
It creates a new scope, so when i is changed in the original scope, it will not be changed in the old scope.

$('select[id*="bodysys"]').each(function (index) {
$(this).change(function () {
if ($("option:selected", this).val() == "99")
enabletext($('input[id$="bodysys' + (index + 1) + 'spec"]')[0]);
});
});
This way works too.

Related

IIFE without parentheses around the function statement

In the following example, concerning closures, I see this:
function addButtons(numButtons) {
for (var i = 0; i < numButtons; i++) {
var button = document.createElement('input');
button.type = 'button';
button.value = 'Button ' + (i + 1);
button.onclick = function(buttonIndex) {
return function() {
alert('Button ' + (buttonIndex + 1) + ' clicked');
};
}(i);
document.body.appendChild(button);
document.body.appendChild(document.createElement('br'));
}
}
window.onload = function() { addButtons(5); };
How come the onclick method isn't defined as follows?:
button.onclick = (function(buttonIndex) {
return function() {
alert('Button ' + (buttonIndex + 1) + ' clicked');
};
})(i);
Doesn't an IIFE require the following syntax: (function statement)(arguments)?
The original code works because the IIFE appears in an assignment, and so there is no ambiguity that the right part of the assignment is indeed an expression.
Without the assignment, the parser would misunderstand it to be a function declaration, and therefore would throw a syntax error, indicating that the declared function lacks a name. In that case the parentheses are necessary to make it an IIFE.
But it is common practice to always include the parentheses for an IIFE, even when used in an assignment.
In the concrete case you have at hand, you can also assign the click handler as using bind, which returns the function it needs:
button.onclick = function(buttonIndex) {
alert('Button ' + (buttonIndex + 1) + ' clicked');
}.bind(null, i);
You can use element's dataset. For example:
function addButtons(numButtons) {
for (var i = 0; i < numButtons; i++) {
var button = document.createElement('input');
button.type = 'button';
button.value = 'Button ' + (i + 1);
button.dataset.buttonIndex = i + 1;
button.onclick = function() {
alert('Button ' + this.dataset.buttonIndex + ' clicked');
};
document.body.appendChild(button);
document.body.appendChild(document.createElement('br'));
}
}
window.onload = function() { addButtons(5); };

Minesweeper Remove event listener in javascript

I've created this two event listening function for my Minesweeper game. When I lose the game, I want to remove the event listeners so that I can't click on the cells after losing. How can I do it?
Thanks
board.oncontextmenu = function(e) {
var cellIndex = e.target.cellIndex;
var rowIndexx = e.target.parentNode.rowIndex;
right_click(rowIndexx, cellIndex);
}
board.onclick = function(e) {
var rowIndex = e.target.cellIndex;
var cellIndex = e.target.parentNode.rowIndex;
console.log("coluna: " + cellIndex + " linha: " + rowIndex);
if (primeira_jogada == 0 ) { timer(); }
if (isBomb(cellIndex, rowIndex) && firstmove == 0) {
moveBomb(cellIndex, rowIndex);
refresh();
}
if (isBomb && primeira_jogada !== 0) {
lose();
//event lister stops here
}
}
Use addEventListener and removeEventListener (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)

Javascript scope of object property

Let's say I want to make a Javascript class for boxes in my page. When an object of that class is made, I want to add a click event to it that would require me accessing one or many of its unique properties. How would I do that? Here's an example:
function Box(boxClassName, originalColor, changeColor){
this.boxClassName = boxClassName;
this.originalColor = originalColor;
this.changeColor = changeColor;
this.initialize = function (){
var html = '<div class="' + this.boxClassName + '></div>';
$(document).append(html);
$(this.boxClassName).css("background-color", originalColor);
// Toggle box color on click
$(this.boxClassName).click(function (){
// this.boxClassName is undefined here, none of this works
if ($("." + this.boxClassName).css("background-color") == originalColor) {
$("." + this.boxClassName).css("background-color", this.changeColor);
} else {
$("." + this.boxClassName).css("background-color", this.originalColor);
}
});
};
this.initialize();
}
There are two ways:
1) Keep a reference to this in a variable and use that:
// Toggle box color on click
var self = this;
$(this.boxClassName).click(function () {
if ($("." + self.boxClassName).css("background-color") == originalColor) {
$("." + self.boxClassName).css("background-color", self.changeColor);
} else {
$("." + self.boxClassName).css("background-color", self.originalColor);
}
});
2) Or bind the click callback to the Box
$(this.boxClassName).click(function () {
if ($("." + this.boxClassName).css("background-color") == originalColor) {
$("." + this.boxClassName).css("background-color", this.changeColor);
} else {
$("." + this.boxClassName).css("background-color", this.originalColor);
}
}.bind(this));
You cannot to access property of Box in onclick event. If you would like to store data of html element, you have to use http://api.jquery.com/jquery.data/. By the way, below code might work for you purpose.
if ($(this).css("background-color") == originalColor) {
$(this).css("background-color", this.changeColor);
} else {
$(this).css("background-color", this.originalColor);
}
First of all, you can bind function to get proper this
$(this.boxClassName).click(function (){
// this.boxClassName is now defined here
if ($("." + this.boxClassName).css("background-color") == originalColor) {
$("." + this.boxClassName).css("background-color", this.changeColor);
} else {
$("." + this.boxClassName).css("background-color", this.originalColor);
}
}.bind(this));
Also consider using slightly different approach
function Box(boxClassName, originalColor, changeColor) {
var changedBg = false, div = $('<div />'), handler = function ( e ) {
$(this).css('background-color', changedBg ? originalColor : changeColor)
changedBg = !changedBg
}
div.addClass(boxClassName)on('click', handler).appendTo(document)
}

Why are all images be changed to the first input

<script type="text/javascript">
var interval;
$('#105').mouseover(function()
{ mouseOver('105'); });
$('#105').mouseout(function()
{ mouseOut('105') ;});
function mouseOver(videoId)
{ var num = 2;
interval = setInterval(function()
{ $('#'+videoId).attr('src', '../thumbs/268255615/268255615.'+num+'.jpg');
if(num == 12)
{ num = 1; }
else
{ num++; }},500); }
function mouseOut (videoId)
{ clearInterval(interval); $('#'+videoId).attr('src', '../thumbs/268255615/268255615.1.jpg'); }
</script>
<script type="text/javascript">
var interval;
$('#104').mouseover(function()
{ mouseOver('104'); });
$('#104').mouseout(function()
{ mouseOut('104') ;});
function mouseOver(videoId)
{ var num = 2;
interval = setInterval(function()
{ $('#'+videoId).attr('src', '../thumbs/325082397/325082397.'+num+'.jpg');
if(num == 12)
{ num = 1; }
else
{ num++; }},500); }
function mouseOut (videoId)
{ clearInterval(interval); $('#'+videoId).attr('src', '../thumbs/325082397/325082397.1.jpg'); }
</script>
The code above is a JavaScript image rotator. The problem with the code is that the last image path always overwrites the image paths before it.
For example if image path one = thumbs/imagea.jpg and if path two = thumbs/imageb.jpg path one ("thumbs/imagea.jpg")then becomes path two on hover becomes ("thumbs/imageb.jpg")
This script worked at one point trying to figure out what is wrong or been changed any ideas?
This is quite obvious: you are redefining mouseOver as a function. The second time you define it, it overwrites the first function. This is because mouseOver is defined on window-scope. Splitting it up in two blocks does not change that. Also note that "interval" is also being defined twice, so a name clash will also occur here.
A solution would be to either use closures, change the name of one of either functions or merge the two functions into one.
Closures are done by wrapping each script in the following block:
(function() {
// your script here
}());
A merged function would be:
var i, setupImage, images;
images = [
{ "id" : "#104", "prefix" : "../thumbs/325082397/325082397." },
{ "id" : "#105", "prefix" : "../thumbs/268255615/268255615." }
];
setupImage = function (image) {
'use strict';
var interval;
$(image.id).mouseover(function () {
var num = 2;
interval = setInterval(function () {
$(image.id).attr('src', image.prefix + num + '.jpg');
if (num === 12) {
num = 1;
} else {
num += 1;
}
}, 500);
});
$(image.id).mouseout(function () {
$(image.id).mouseout(function () {
clearInterval(interval);
$(image.id).attr('src', image.prefix + '1.jpg');
});
});
};
for (i = 0; i < images.length; i += 1) {
setupImage(images[i]);
}

How can I re enable a setInterval after I called clearInterval?

Here's my javascript:
<script type="text/javascript">
var timer;
$(document).ready(function () {
timer = setInterval(updatetimerdisplay, 1000);
$('.countdown').change(function () {
timer = setInterval(updatetimerdisplay, 1000);
});
function updatetimerdisplay() {
$(".auctiondiv .auctiondivleftcontainer .countdown").each(function () {
var newValue = parseInt($(this).text(), 10) - 1;
$(this).text(newValue);
if (newValue >= 9) {
$(this).css("color", "");
$(this).css("color", "#4682b4");
}
if (newValue == 8) {
$(this).css("color", "");
$(this).css("color", "#f3982e");
}
if (newValue == 5) {
$(this).css("color", "");
$(this).css("color", "Red");
}
if (newValue <= 1) {
//$(this).parent().fadeOut();
clearInterval(timer);
}
});
}
});
var updateauctionstimer = setInterval(function () {
$("#refreshauctionlink").click();
}, 2000);
function updateauctions(response) {
var data = $.parseJSON(response);
$(data).each(function () {
var divId = "#" + this.i;
if ($(divId + " .auctiondivrightcontainer .latestbidder").text() != this.b) {
$(divId + " .auctiondivrightcontainer .latestbidder").fadeOut().fadeIn();
$(divId + " .auctiondivrightcontainer .auctionprice .actualauctionprice").fadeOut().fadeIn();
$(divId + " .auctiondivleftcontainer .countdown").fadeOut().fadeIn();
}
$(divId + " .auctiondivrightcontainer .latestbidder").html(this.b);
$(divId + " .auctiondivrightcontainer .auctionprice .actualauctionprice").html(this.p);
if ($(divId + " .auctiondivleftcontainer .countdown").text() < this.t) {
$(divId + " .auctiondivleftcontainer .countdown").html(this.t);
}
});
}
</script>
Basically, I want to turn the timer back on, if any .countdown element has it's text change.
The text will change because of an AJAX call I use to update that value.
Currently the timer doesn't re enable and the countdown freezes after the value of .Countdown is changed. I think that the change() event fires when the text of an element changes. Is this correct?
Any glaring mistakes on my part?
Your code contains a loop and condition:
function updatetimerdisplay() {
$(".auctiondiv .auctiondivleftcontainer .countdown").each(function () {
...
if (newValue <= 1) {
//$(this).parent().fadeOut();
clearInterval(timer);
}
...
}
}
It's very likely that one of these elements have a value which satisfy the condition newValue <= 1. In that case, the timer will stop. Even when you change the contents of an input field, the timer will immediately stop after that run.
If you have to support multiple timers, use a wallet of timers (var timers = {};timers.time1=... or var timers = [];timers[0] = ...). If you have to support only a few timeouts, you can even use variables (var timer1=... ,timer2=..., timer3=...;).
You are trying to bind the change event before the elements exist. Put that code inside the ready event handler:
$(document).ready(function () {
timer = setInterval(updatetimerdisplay, 1000);
$('.countdown').change(function () {
timer = setInterval(updatetimerdisplay, 1000);
});
});
You also might want set the timer variable to an identifiable value when the timer is off (e.g. null), so that you can check for that value before you start a timer to prevent from starting multiple timers.

Categories

Resources