Disabling a button after a click event - javascript

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.

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.

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

JavaScript event being overwritten in for loop

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

read class and apply css with javascript or jquery

I wanna apply css with short class name with number.
for example,
if I use class name mt-100, it means margin-top:100px.
if I use class name mr-200, it means margin-right:200px.
if I use class name mt-100 mr-200, it means margin-top:100px and margin-right:200px.
if I use class name pt-100 mt-100 mr-200, it means padding-top:100px and margin-top:100px and margin-right:200px.
I try to make it but it does not work.
I do not want to make every class in css like this --> .mt-100{margin-top:100}
could you help me how to do make this?
thank you in advance.
let me show you my code below,
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
function classStartsWith(str) {
return $('div').map( function(i,e) {
var classes = e.className.split(' ');
for (var i=0, j=classes.length; i < j; i++) {
if (classes[i].substr(0, str.length) == str) return e;
}
}).get();
}
function classEndWith(str) {
return $('div').map( function(i,e) {
var classes = e.className.split(' ');
for (var i=0, j=classes.length; i < j; i++) {
if (classes[i].indexOf('mt-') || classes[i].indexOf('mb-') || classes [i].indexOf('mr-') || classes[i].indexOf('ml-') || classes[i].indexOf('pt-') || classes[i].indexOf('pb-') || classes[i].indexOf('pr-') || classes[i].indexOf('pl-'))
{
var ct = classes[i].split('-');
var cts = ct[1];
}
if (classes[i].substr(0, str.length) == str) return e,cts;
}
}).get();
}
$(document).ready(function(){
$(classStartsWith('mt-')).each(function(){
$(this).css('margin-top', classEndWith('mt-')+'px');
});
$(classStartsWith('mb-')).each(function(){
$(this).css('margin-bottom', classEndWith('mb-')+'px');
});
$(classStartsWith('mr-')).each(function(){
$(this).css('margin-right', classEndWith('mr-')+'px');
});
$(classStartsWith('ml-')).each(function(){
$(this).css('margin-left', classEndWith('ml-')+'px');
});
$(classStartsWith('pt-')).each(function(){
$(this).css('padding-top', classEndWith('pt-')+'px');
});
$(classStartsWith('pb-')).each(function(){
$(this).css('padding-bottom', classEndWith('pb-')+'px');
});
$(classStartsWith('pr-')).each(function(){
$(this).css('padding-right', classEndWith('pr-')+'px');
});
$(classStartsWith('pl-')).each(function(){
$(this).css('padding-left', classEndWith('pl-')+'px');
});
});
</script>
</head>
<body>
<div class="mt-100 mb-200" style="width:300px;height:300px;border:1px solid red">
aaaa
</div>
<div class="pt-200 mb-200" style="width:300px;height:300px;border:1px solid red">
bbb
</div>
<div class="pr-300 ml-300 mt300" style="width:300px;height:300px;border:1px solid red">
ccc
</div>
<div class="pl-200 mt200" style="width:300px;height:300px;border:1px solid red">
ddd
</div>
</body>
The way you handle it now presents way too much overhead for this kind of task.
I recommend you to learn more about using the data attribute on your HTML tags. These attributes allow you to define tag specific settings which you can easily read with jQuery and make it respond to the data.
Example:
<div class="my-div-class" data-mt="100" data-mb="200">...</div>
<div class="my-div-class" data-pt="200" data-mb="200">...</div>
<script>
$(function() {
// Walk through each element with this class
$('.my-div-class').each(function() {
var thisDiv = $(this), // cache this element
thisData = thisDiv.data(), // get all data attributes
thisCSS = {}; // create the css array
// Check which data is set and update the css accordingly
if (thisData['mt']) {
thisCSS['margin-top'] = thisData['mt'] + 'px';
}
if (thisData['mb']) {
thisCSS['margin-bottom'] = thisData['mb'] + 'px';
}
if (thisData['pt']) {
thisCSS['padding-top'] = thisData['pt'] + 'px';
}
if (thisData['pb']) {
thisCSS['padding-bottom'] = thisData['pb'] + 'px';
}
// Add the css to this element
thisDiv.css(thisCSS);
// The following two lines show the data in each div for debugging.
// Remove these lines when you don't need this info anymore.
thisDiv.append('<div>CSS: ' + JSON.stringify(thisCSS) + '</div>');
thisDiv.append('<div>DATA: ' + JSON.stringify(thisData) + '</div>');
});
});
</script>
Here is the JSFiddle.
And here is the jQuery Documentation on .data().
Also check out the data-attribute documentation here.

How can I consolidate duplicated javascript functions?

I have a site to allow someone to place food orders. Images of potential ingredients (determined by a MySQL query) can be clicked to add or remove them, and the image will toggle on each click.
The problem I'm having is for each new item I am having to duplicate the function and just change the variable names for each new function. I'm sure there must be a way to simplify to dynamically apply to all of the ingredients without all of the redundant code.
Here is the code just for two. There are dozens. Any suggestions would be appreciated.
window.onload = function () {
var ProductElement = document.getElementById('Ketchup');
if (ProductElement != null) {
Ketchupobj = document.getElementById('Ketchup')
document.getElementById('Ketchuptogg').onclick = function () {
Ketchuptoggle();
}
}
var ProductElement = document.getElementById('Mustard');
if (ProductElement != null) {
Mustardobj = document.getElementById('Mustard')
document.getElementById('Mustardtogg').onclick = function () {
Mustardtoggle();
}
}
}
function Ketchuptoggle() {
if (Ketchuptggle == 'on') {
Ketchupobj.src = "Ketchup.jpg";
Ketchuptggle = 'off';
} else {
Ketchupobj.src = "noKetchup.jpg";
Ketchuptggle = 'on';
}
}
function Mustardtoggle() {
if (Mustardtggle == 'on') {
Mustardobj.src = "Mustard.jpg";
Mustardtggle = 'off';
} else {
Mustardobj.src = "noMustard.jpg";
Mustardtggle = 'on';
}
}
<table class="ing">
<tr>
<?php
for ($x=0; $x<5 AND $row = mysql_fetch_row($result);$x++ ) {
$caps=$row[1];
$caps=strtoupper($caps);
echo <<<image
<td><b>$caps</b><br>
<a id="$row[0]" class="toggle" href="#"><img id="$row[0]img" class="toggimg"
src="$row[0].jpg" style="border-style: none" alt=""/></a>
</td>
image;
}
echo"</tr></table>";
Implicit this is your friend:
var toggles = document.getElementsByClassName('toggle');
for (var i=0; i<toggles.length; i++) {
toggles[i].isOn = true;
toggles[i].onclick = function(ev){
var condiment = this.id;
this.isOn = !this.isOn;
document.getElementById(condiment+'img').src=(this.isOn?'':'no')+condiment+'.png';
};
}
With html you have the ability to add your property for an element, so you could do:
<button class="btnProduct" data-type="mostard"> Mostard</button>
<button class="btnProduct" data-type="ketchup"> Ketchup</button>
<button class="btnProduct" data-type="barbecue"> Barbecue</button>
Then with a help of jquery you can do:
$('btnProduct').click(function(){
//So, here you could use a switch or some logic
// to do different things for data-type
console.log($(this).attr('data-type'))
}

Categories