JavaScript event being overwritten in for loop - javascript

I am creating JavaScript events on items within a loop, but every time I fire the event it only ever fires the last event created.
JavaScript:
var dirLinks = document.getElementsByClassName("dirLink"),
iframe = document.getElementById("tmpImg");
showDir.addEventListener('click', showDirContent, false);
showImgs.addEventListener('click', showImgsContent, false);
for (var i = 0; i < dirLinks.length; i++) {
var link = dirLinks[i];
link.onclick = function () {
updateIframeSource(link.getAttribute("imgSrc"));
}
}
function updateIframeSource(source) {
iframe.src = source;
}
HTML:
<a class="dirLink" imgSrc="img1.jpg" href="#">img1.jpg</a><br />
<a class="dirLink" imgSrc="img2.jpg" href="#">img2.jpg</a><br />
<a class="dirLink" imgSrc="img3.jpg" href="#">img3.jpg</a><br />
<a class="dirLink" imgSrc="img4.jpg" href="#">img4.jpg</a><br />
<a class="dirLink" imgSrc="img5.jpg" href="#">img5.jpg</a>
<iframe id="tmpImg"></iframe>
No matter which link I click on, it will always hit the updateIframeSource function with img5.jpg passed in.

It's because in javascript for loop don't create new scope in each iteration (only functions does) so you reference one variable link that in a function that is executed when loop is finished so it's always 5, to fix this just wrap the whole thing in anonymous function like this:
for(var i = 0; i < dirLinks.length; i++) {
(function(link) {
link.onclick = function () {
updateIframeSource(link.getAttribute("imgSrc"));
};
})(dirLinks[i]);
}

This is because the loop does not create a new scope. Because javascript has function scope:
var bindEvent = function(intId){
var link = dirLinks[intId];
link.onclick = function () {
updateIframeSource(link.getAttribute("imgSrc"));
}
}
for(var i = 0; i < dirLinks.length; i++) {
bindEvent(i);
}
see jsfiddle

use also this
for(var i = 0; i < dirLinks.length; i++) {
var link = dirLinks[i];
link.addEventListener("click", updateIframeSource());
}
function updateIframeSource() {
return (function(event){
iframe.src = event.target.getAttribute("imgSrc");
alert(iframe.src);
});
}

The operation of assign an eventhandler are expensive it's better wrap all anchor links and use event delegation:
here how:
<div id="container">
<a class="dirLink" imgSrc="img1.jpg" href="#">img1.jpg</a><br />
<a class="dirLink" imgSrc="img2.jpg" href="#">img2.jpg</a><br />
<a class="dirLink" imgSrc="img3.jpg" href="#">img3.jpg</a><br />
<a class="dirLink" imgSrc="img4.jpg" href="#">img4.jpg</a><br />
<a class="dirLink" imgSrc="img5.jpg" href="#">img5.jpg</a>
</div>
<script>
var dirLinks = document.getElementsByClassName("dirLink");
var iframe = document.getElementById("tmpImg");
// Get the container
var container = document.getElementById("container");
//showDir.addEventListener('click', showDirContent, false);
//showImgs.addEventListener('click', showImgsContent, false);
container.addEventListener('click', function(evt){
// You can send the event or extract like this the value of "imgsrc"
updateIframeSource(evt.target.attributes.imgsrc.value);
});
function updateIframeSource(source) {
iframe.src = source;
}
</script>

Here is another way with forEach loop
HTML:
<a class="dirLink" imgSrc="img1.jpg" href="#">img1.jpg</a>
<br />
<a class="dirLink" imgSrc="img2.jpg" href="#">img2.jpg</a>
<br />
<a class="dirLink" imgSrc="img3.jpg" href="#">img3.jpg</a>
<br />
<a class="dirLink" imgSrc="img4.jpg" href="#">img4.jpg</a>
<br />
<a class="dirLink" imgSrc="img5.jpg" href="#">img5.jpg</a>
<iframe id="tmpImg"></iframe>
JS:
var dirLinks = document.getElementsByClassName("dirLink");
var iframe = document.getElementById("tmpImg");
[].forEach.call(dirLinks, (l) => {
l.addEventListener('click', function() {
updateIframeSource(l.getAttribute("imgSrc"));
})
})
function updateIframeSource(source) {
iframe.src = source;
}

Related

Cache using for onclick element on multilang page

I am making multi-lang index page and I'm making lang change area, when I click each language text it changes.
When I click my language links(AZ, EN, RU) it changes language but after the page reload it doesn't change language.
Mainly I want caching onclick functions after a page reload.
Also I want to use pure JavaScript.
Here is my code:
var voc = [
{
"AZ":"Log in2",
"EN":"Log in",
"RU":"Log in3"
}
];
function translate(ele,lng){
for(var i=0;i<voc.length;i++){
for(var k in voc[i]){
if(voc[i][k] == ele.innerText.trim()){
ele.innerText = voc[i][lng];
break;
}
}
}
}
function translateTo(lng){
var trc = document.getElementsByClassName("trans");
for(var i=0;i<trc.length;i++){
translate(trc[i],lng);
}
}
//add this function to any event button.click,select.change or on load
//translateTo("AR");
function under1(){
document.getElementsByClassName("lang")[0].style = "text-decoration:underline;";
document.getElementsByClassName("lang")[1].style = "text-decoration:none";
document.getElementsByClassName("lang")[2].style = "text-decoration:none";
}
function under2(){
document.getElementsByClassName("lang")[0].style = "text-decoration:none;";
document.getElementsByClassName("lang")[1].style = "text-decoration:underline";
document.getElementsByClassName("lang")[2].style = "text-decoration:none";
}
function under3(){
document.getElementsByClassName("lang")[0].style = "text-decoration:none;";
document.getElementsByClassName("lang")[1].style = "text-decoration:none";
document.getElementsByClassName("lang")[2].style = "text-decoration:underline";
}
.langselect a{
text-decoration:none;
}
.langselect a:nth-child(2){
text-decoration:underline;
}
<p>
<span class='trans'>Log in</span>
</p>
<p class="langselect">
<a href="" class="lang" onclick='translateTo("AZ"); under1(); return false;'>AZ</a>
<a href="" class="lang" onclick='translateTo("EN"); under2(); return false;'>EN</a>
<a href="" class="lang" onclick='translateTo("RU"); under3(); return false;'>RU</a>
</p>
The answer would be using a cookie:
window.onbeforeunload = function() {
document.cookie = "lang=AU"; //For example. You can choose to add the language whichever way you want.
}
And then when the page loads:
window.onload = function() {
window.getCookie = function(name) {
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
if (match) {
return match[2]
};
}
Courtesy of #JonathanCamenisch for the second part of the answer.

create multiple arrays on different elements

I'm trying to set a function in my application which allows the user to click on a button and then click the submit button which displays an image, but I want the buttons to hold more than one image and randomly select an image from the array.
How can I do this?
<div id='prefPage'>
<header id='header2pref'>
<div id='title2pref'>PREFERENCES</div>
</header>
<div id='body'>
<div id='leftAlign'>
<div id="foodpicloc">
</div>
</div><button id='myBtn2'>SET PREFRENCES</button>
<div id='rightAlignPref'>
<div id=fixed>
<div>
<button id="button1">BURGER</button>
<button id="button2">HOTDOG</button>
</div>
</div>
</div>
</div>
</div>
var button1 = document.getElementById("button1");
var button2 = document.getElementById("button2");
var preference = document.getElementById("preference");
var foodpic = document.getElementById("foodpiclocation");
var foodpic;
button1.addEventListener('click', function() {
foodpicurl = 'burger.svg';
});
button2.addEventListener('click', function() {
foodpicurl = 'hotdog.svg';
});
preference.addEventListener('click', function() {
var foodpic = document.createElement('img');
foodpic.src = foodpicurl;
foodpiclocation.innerHTML = '';
foodpiclocation.appendChild(foodpic);
});
Clean solution using vanilla Javascript. NOTE: I suggest you add this to your HTML code <div id="foodpicloc"><img id="foodpic"></div> in your HTML first. Changing the image's src is quicker and cleaner than appending a new image element everytime the image changes.
Define
function mapClickToImage(imageSelector, updateBtnSelector, btnSectorToImageSrcMapping) {
var currentImageSrc = null;
var imageElement = document.querySelector(imageSelector);
for (var btnSelector in btnSectorToImageSrcMapping) {
var buttonElement = document.querySelector(btnSelector);
buttonElement.addEventListener('click', function() {
currentImageSrc = btnSectorToImageSrcMapping[btnSelector];
});
var updateButtonElement = document.querySelector(updateBtnSelector);
updateButtonElement.addEventListener('click', function() {
if (currentImageSrc) {
imageElement.src = currentImageSrc;
}
});
}
Usage
mapClickToImage('#foodpic', '#preference', {
'#button1': 'burger.svg',
'#button2': 'hotdog.svg'
});

How can I create a function inside an $.click (jquery) that uses an id from the $.click

So, as I think, my title is not pretty understandable.
I have this jquery code:
$("img.slideimg").click(function(){
var id = $(this).attr('id');
$("img.previewimg." + id).css({"display": "block"});
$("div.imgpreview").css({"display": "flex"});
function slideDo(n) {
var i;
var aux = id - 1 + n;
var slidesp = document.getElementsByClassName("previewimg");
if (aux > slidesp.length) {aux = 1}
if (aux < 1) {aux = slidesp.length}
for (i = 0; i < slides.length; i++) {
slidesp[i].style.display = "none";
}
slidesp[aux-1].style.display = "block";
}
});
The problem is that the browser console output is this:
Uncaught ReferenceError: slideDo is not defined
at HTMLAnchorElement.onclick (index.html:85)
My problem is that I want to create a function that uses an variable from the $("img.slideimg").click event. This variable is id = $(this).attr('id'); so I thinked of creating the function inside it. Apparently it doesn't work like this so I need a little help.
Sorry if you don't understand me. I'm pretty new to this kind of coding :(
HTML where i use slideDo
<div class="middle">
<a class="prev" onclick="slideDo(-1)"> ❮ </a>
<div class="imglink">
<img src="img/dailyui/008.png" class="previewimg 1">
<img src="img/dailyui/007.jpg" class="previewimg 2">
<img src="img/dailyui/006.jpg" class="previewimg 3">
<img src="img/dailyui/003.jpg" class="previewimg 4">
</div>
<a class="next" onclick="slideDo(1)"> ❯ </a>
</div>
So what I want to do:
I have a slideshow and when I click on one of the pictures, a modal with the pictures will show up. Then here I have again another buttons for next / previous picture but they doesn't seems to work. Here is the demo website of my code: beta.eduardstefan.com
The scope of the name slideDo is just the click function, but it appears you're trying to call it from the global scope (the onclick attribute of an anchor). You need to assign the function to a global variable.
var slideDo = function() {}; // initially does nothing
$(document).ready(function() {
$("img.slideimg").click(function(){
var id = $(this).attr('id');
$("img.previewimg." + id).css({"display": "block"});
$("div.imgpreview").css({"display": "flex"});
slideDo = function(n) {
var i;
var aux = id - 1 + n;
var slidesp = document.getElementsByClassName("previewimg");
if (aux > slidesp.length) {aux = 1}
if (aux < 1) {aux = slidesp.length}
for (i = 0; i < slides.length; i++) {
slidesp[i].style.display = "none";
}
slidesp[aux-1].style.display = "block";
}
});
});

Disabling a button after a click event

I have this piece of HTML code
<html>
<head></head>
<body>
<div ng-init="controller.onInit()" style="divContainer">
<div class="divLoading" style="vertical-align:middle" ng-show="controller.noOfLoadingInProgress > 0">
<span class="text"> Loading ...</span> <img src="../../Styles/Images/loading.gif" />
</div>
<br />
<h1>
Test</h1>
<div ui-view="wizardContent">
</div>
<!--<div class="clear">
</div>-->
<div>
<a class="buttonprev" id="btnPrevious" href="#" ng-show="controller.wizard.wizardIndex > 1"
ng-click="controller.wizard.previous()"><span>Previous </span></a>
<a class="buttonCancel"
id="btnCancel" href="#" ng-click="controller.wizard.cancel()"><span>Cancel </span>
</a>
<a class="buttonnext" id="btnNext" ng-disabled="controller.wizard.isNextInProgress"
href="#" ng-show="controller.termsAndCondition.isTermAndConditionAccepted && (controller.wizard.wizardIndex < controller.wizard.wizardItems.length-1)"
ng-click="controller.wizard.next()"><span>Next</span> </a>
<a class="buttonnext" id="btnFinish" href="#" ng-show="controller.termsAndCondition.isTermAndConditionAccepted && (controller.wizard.wizardIndex == controller.wizard.wizardItems.length-1)"
ng-click="controller.wizard.finish()" ng-disabled ="controller.wizard.isFinished == 1"><span>Finish</span> </a>
</div>
</div>
</body>
</html>
And this piece of javascript code.
var WizardItem = function (manager, uiState) {
this.manager = manager;
this.uiState = uiState;
}
var Wizard = function ($state, onFinishCallback, wizardItems) {
var self = this;
self.onFinishCallback = onFinishCallback;
self.wizardItems = wizardItems;
self.wizardIndex = 0;
self.isNextInProgress = false;
self.isFinished = 0;
self.refresh = function () {
$state.go(wizardItems[self.wizardIndex].uiState);
};
self.next = function () {
if ((self.wizardIndex < wizardItems.length - 1) && wizardItems[self.wizardIndex].manager.validate()) {
if (wizardItems[self.wizardIndex].manager.overrideNext == null) {
self.wizardIndex++;
$state.go(wizardItems[self.wizardIndex].uiState);
}
else {
self.isNextInProgress = true;
wizardItems[self.wizardIndex].manager.overrideNext(onFinishCallBack);
}
}
function onFinishCallBack(success) {
self.isNextInProgress = false;
if (success) {
self.wizardIndex++;
$state.go(wizardItems[self.wizardIndex].uiState);
self.isFinished = 1;
}
}
}
self.refreshWizardFrom = function (newWizardItems) {
self.wizardItems.splice(0);
for (var c = 0; c < newWizardItems.length; c++) {
self.wizardItems.push(newWizardItems[c]);
}
}
self.previous = function () {
if (self.wizardIndex > 1) {
self.wizardIndex--;
console.log($state.go(wizardItems[self.wizardIndex].uiState));
$state.go(wizardItems[self.wizardIndex].uiState);
}
};
self.cancel = function () {
if (confirm('Are you sure you want to cancel!')) {
$state.go('Home');
}
};
self.finish = function () {
self.isFinished = 1;
if ((self.wizardIndex == wizardItems.length - 1) && wizardItems[self.wizardIndex].manager.validate()) {
//Ajmal Bug 410 - Variable flag isFinished set to 1 and being called on finish button click to disable it
self.isFinished = 1;
self.onFinishCallback();
self.isFinished = 1;
// alert('finish');
}
};
self.validateCurrentWizardItem = function () {
return wizardItems[self.wizardIndex].manager.validate();
};
self.initAllWizardItems = function () {
for (var c = 0; c < wizardItems.length; c++) {
wizardItems[c].manager.onInit();
}
}
self.registerValidations = function () {
for (var c = 0; c < wizardItems.length; c++) {
wizardItems[c].manager.registerValidations();
}
};
};
I would like to disable the finish button after clicking it once.
I've tried something like that, but it still doesn't work
in the javascript file, use a flag
self.isFinished = 0;
then set it to 1 in the finish function
self.isFinished = 1
then use ng-disabled in the html part of the code
ng-disabled = "controller.wizard.isFinished == 1"
Can someone figure out where may be the issue ?
Thanks
Try do self.wizadr.isFinished = 1; instead of self.isFinished = 1;
You cannot disable tag. Use ng-disabled on button. Also add ng-app directive on body
Indeed, disabling a tag did not make any sense, hence I decided to remove all the links from all the tags with this function.
In the self.finish function, added a call to a function (in bold )
self.finish = function () {
if ((self.wizardIndex == wizardItems.length - 1) && wizardItems[self.wizardIndex].manager.validate()) {
self.onFinishCallback();
ConvertAnchorToSpan();
// alert('finish');
}
};
Outside of the Wizard, used that function in the same javascript file.
function ConvertAnchorToSpan() {
var $link = $('a');
var $span = $('<span>');
$link.after($span.html($link.html())).remove();
}
It now works and prevents multiple submissions. I removed all the isFinished flags in the javascript file as well as the ng-disabled in the html.
As there is no disable property for anchor tag so you can use custom code for that.
I used ng-class in place of ng-disabled It will add a class to your anchor tag and in css code is written for make this class elements disable.
<style>
.disabledOn {
cursor: not-allowed;
pointer-events: none;
color: grey;
}
</style>
HTML
<a class="buttonnext" id="btnFinish" href="#" ng-show="controller.termsAndCondition.isTermAndConditionAccepted && (controller.wizard.wizardIndex == controller.wizard.wizardItems.length-1)"
ng-click="controller.wizard.finish()" ng-class="{disabledOn : controller.wizard.isFinished == 1}"><span>Finish</span> </a>
Best of luck :)
ng-disabled can't be used for a tag. you can use this
HTML
<a ng-click="disabled()" class="btn" ng-class="{'disabled':disable}">Click Me</a>
JS
app.controller('MainCtrl', function($scope) {
var count=0;
$scope.disable=false;
$scope.disabled = function() {
if(count>0) { return false;}else{
alert("do someting else");
$scope.disable=true;
count++;
}
}
});
CSS
.disabled { cursor: default; opacity: .5; }
You can prevent click event by using this code after a first click.
For reference click this link
Hope it will be useful for you.

Javascript to image cycle

Simple request, but I don't know how to do it. I've got a series of 10 images (image0.gif, image1.gif image2.gif etc...) that need to change to the next image in the sequence (cycling around after 9) when another image is pressed. This is what I have so far...
<html>
<head></head>
<body bgcolor="#808080">
<script type="text/javascript">
var c = 0;
function preload(img) {
var a = new Image();
a.src = img;
return a;
}
if (needed) {
time0 = preload("image0.gif");
time1 = preload("image1.gif");
time2 = preload("image2.gif");
time3 = preload("image3.gif");
time4 = preload("image4.gif");
time5 = preload("image5.gif");
time6 = preload("image6.gif");
time7 = preload("image7.gif");
time8 = preload("image8.gif");
time9 = preload("image9.gif");
}
function clickme() {
// update image
c += 1;
// alert(c)
}
</script>
<div align="center">
<center>
<img src="images/image0.gif" width="20" height="55" name="time0"> <a href="#" onMouseDown="return clickme()">
<img src="images/button.gif" border="0" width="96" height="55">
</a>
</td>
</tr>
</table>
</center>
</div>
</body>
</html>
First, you can and should take advantage of the fact, that only thing diferrent in the each umage name is number. So, you can store number and create any image name:
function getImage(id) {
return "image"+id+".gif";
}
Then, you should have a way to acces the image that you want to change. Like adding id to he element:
<img id="changing" src="image0.png" />
There should be onclick used, not onmousedown. User may change his mind and hower the mouse away - that is not click:
<a href="#" onclick="clickme()" />
Finally, changing the image element:
var c=0;
var max = 9;
function clickme() {
c++;
if(c>max)
c=0; //looping back to zero
docment.getElementById("changing").src = getImage(c); //getImage is defined above
}
Put an id on the image (the-image, for instance).
function clicme() {
c += 1;
document.getElementById('the-image')
.setAttribute('src', 'image' + (c % 10) + '.gif');
}
Also there is no href element. I think you meant to type <a href.

Categories