How to make sure that click functions are only performed once - javascript

When the user clicks on either .class or #id, some changes are made to the css of both divs and the value of #id increases by 1. However, when the user clicks on either one of the divs, the changes should only be made once - if the user clicks again, nothing will happen unless the page is refreshed.
$('.class, #id').one('click', function(e) {
$('.class, #id').css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff',
});
$("#id").html(function(i, val) { return val*1+1 });
});
Above shows the code that I am using. As you can see, I have used .one to make sure that the code is only performed once. This works, but the problem is that the user can click on .class and then click on #div which means that the code can be performed twice.
How would I edit this so that the code can only be performed once - clicking on one div means the other div can not be clicked on.

You can set a data attribute on both objects and only increment the counter if that is not set:
$('.class, #id').one('click', function(e) {
if (!$(this).data("valueSet")) {
$('.class, #id').css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff'
}).data("valueSet", true);
$("#id").html(function(i, val) { return val*1+1 });
}
});
Or, if you know there are no other jQuery click handlers that you want to retain, you can unbind all jQuery click handlers from both objects:
$('.class, #id').one('click', function(e) {
$('.class, #id').off("click").css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff'
})
$("#id").html(function(i, val) { return val*1+1 });
});
Or, you can unbind just this specific event handler by putting the event handler in a named function:
function oneClick(e) {
$('.class, #id').off("click", oneClick).css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff'
})
$("#id").html(function(i, val) { return val*1+1 });
}
$('.class, #id').one('click', oneClick);
A little more generic scheme would create a custom function that will only ever perform its action once:
function oneAction(fn) {
var calledYet = false;
return function() {
if (!calledYet) {
calledYet = true;
return fn.apply(this, arguments);
}
}
}
Then, you can use this:
$('.class, #id').one('click', oneAction(function(e) {
// this will only ever be executed once
$('.class, #id').css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff'
})
$("#id").html(function(i, val) { return val*1+1 });
}));

I think you could use one with event delegation instead. That way you have a single handler for all targets and jQuery will automatically remove it once invoked.
$(document).one('click', '#first,#second', alert.bind(null, 'clicked'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="first">first</button>
<button id="second">second</button>
With your code it would be:
$(document).one('click', '.class, #id', function(e) {
//handle click
});
Here's another example showing how you could manually remove the handler after invocation in a safe way (without affecting other handlers) using a named function expression:
$('#first, #second').click(function someClickHandler(e) {
alert('clicked!');
$('#first, #second').off('click', someClickHandler);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="first">First</button>
<button id="second">Second</button>

You are setting two listeners, in fact. One on the .class and another on the #id.
This means you'll need to store a state variable and check it before performing any action.
var isClickable = true;
$('.class, #id').one('click', function(e) {
if(isClickable){
isClickable = false;
$('.class, #id').css({
'background-color' : 'rgb(232,69,73)',
'color' : '#fff',
});
$("#id").html(function(i, val) { return val*1+1 });
}
});
This is a better option than adding a state attribute to the actual DOM element.

Related

target specific class onclick

Hi I have 2 classes which have an on click event on it, How can I target the event on click that would not affect the other class. Basically let's say I have two classes of scroller-right, I just want to affect the class that is being click.
This what I have so far
$('.scroller-right').click(function(e) {
$('.scroller-left').fadeIn('slow');
$('.scroller-right').fadeOut('slow');
$('.tab-scroll').animate({left:"+="+widthOfHidden()+"px"},'slow',function(){
});
});
$('.scroller-left').click(function() {
$('.scroller-right').fadeIn('slow');
$('.scroller-left').fadeOut('slow');
$('.tab-scroll').animate({left:"-="+getLeftPosi()+"px"},'slow',function(){
});
});
try to use '$(this)' variable inside function liek below
$('.scroller-left').click(function() {
$('.scroller-right').fadeIn('slow');
$(this).fadeOut('slow');
});
You correctly observed that you need a single function. As a result, we need to write a function which can handle both cases and add it as a handler for both.
function scrollerClick(e) {
var isLeft = $(this).hasClass("scroller-left");
$('.scroller-' + (isLeft ? "left" : "right")).fadeIn('slow');
$('.scroller-' + (!isLeft ? "left" : "right")).fadeOut('slow');
$('.tab-scroll').animate({left:"+="+widthOfHidden()+"px"},'slow',function(){
});
}
$('.scroller-right, .scroller-left').click(scrollerClick);

Backbone: Toggle methods on some event

I want one button to toggle two methods in backbone but I'm having issues. I'm pretty much new to JS in general.
If you click on a button:
I want to show a hidden div
change the text of the button clicked
Then, if you click the button again (which has the new text and the hidden div is shown)
Change the text
Hide the shown div
The second method of .hide is not being fired? I'm wondering if this is because .hide is not in the DOM initially, because it's being added on the show method. Just a guess and maybe there's a better way to toggle methods on one class?
Here's my JS
'touchstart .share-btn' : 'show',
'touchstart .hide' : 'hide'
'show' : function (e) {
var view = this;
$(e.currentTarget).closest('.tile').find('.share-tools').fadeIn('fast');
$(e.currentTarget).addClass('hide');
if ($(e.currentTarget).hasClass('hide')){
$(e.currentTarget).find('.button-copy').closest('.button-copy').html('close');
}
},
'hide' : function (e) {
var view = this;
if($(e.currentTarget).hasClass('hide')) {
$('.share-tools').fadeOut('fast');
$(e.currentTarget).removeClass('hide');
$(e.currentTarget).find('.button-copy').closest('.button-copy').html('share');
}
},
Maybe reworking your code a bit will help. I've created a working jsfiddle based on what I think you're trying to accomplish.
Here is the relevant view code:
var View = Backbone.View.extend({
...
// Make it clear that these are the same element.
// Ensure they will not both fire by making them exclusive.
events: {
'mousedown .share-btn:not(.hide)' : 'show',
'mousedown .share-btn.hide' : 'hide'
},
'show' : function (e) {
console.log('show');
var $e = $(e.currentTarget);
$e.closest('.tile').find('.share-tools').fadeIn('fast', function () {
$e.addClass('hide');
});
$e.find('.button-copy').closest('.button-copy').html('close');
},
'hide' : function (e) {
console.log('hide');
var $e = $(e.currentTarget);
$e.closest('.tile').find('.share-tools').fadeOut('fast', function () {
$e.removeClass('hide');
});
$e.find('.button-copy').closest('.button-copy').html('share');
}
});
You can find the working jsfiddle here: http://jsfiddle.net/somethingkindawierd/7rfs9/
Try to return false in your event listener to prevent call both methods on first click.

Invoking jQuery toggle method inside object literal

I'm struggling to get the below piece of code working. The problem is that when I wrap the two functions in the editItems property inside the parenthesis (), the code behaves strangely and assigns display: none inline css property to the edit button.
If I don't wrap the two functions inside the parenthesis, I get a javascript syntax error function statement requires a name.
var shoppingList = {
// Some code ...
'init' : function() {
// Capture toggle event on Edit Items button
(shoppingList.$editButton).toggle(shoppingList.editItems);
},
'editItems' : function() {
(function() {
$(this).attr('value', 'Finish editing');
(shoppingList.$ingrLinks).unbind('click', shoppingList.ingredients) // disable highlighting items
.removeAttr('href');
$('.editme').editable("enable");
$('.editme').editable('http://localhost:8000/edit-ingredient/', {
indicator : 'Saving...',
tooltip : 'Click to edit...',
submit : 'OK',
cancel : 'Cancel'
});
}), (function() {
$(this).attr('value', 'Edit item');
(shoppingList.$ingrLinks).attr('href', '#');
$('.editme').editable("disable");
(shoppingList.$ingrLinks).bind('click', shoppingList.ingredients) // re-enable highlighting items
})
}
}
$(document).ready(shoppingList.init);
However, if I invoke the toggle event "directly" like this, it works:
var shoppingList = {
// Some code ...
'init' : function() {
// Toggle event on Edit Items button
(shoppingList.$editButton).toggle(
function() {
$(this).attr('value', 'Finish editing');
(shoppingList.$ingrLinks).unbind('click', shoppingList.ingredients) // disable highlighting items
.removeAttr('href');
$('.editme').editable("enable");
$('.editme').editable('http://localhost:8000/edit-ingredient/', {
indicator : 'Saving...',
tooltip : 'Click to edit...',
submit : 'OK',
cancel : 'Cancel'
});
}, function() {
$(this).attr('value', 'Edit item');
(shoppingList.$ingrLinks).attr('href', '#');
$('.editme').editable("disable");
(shoppingList.$ingrLinks).bind('click', shoppingList.ingredients) // re-enable highlighting items
});
}
};
$(document).ready(shoppingList.init);
Is there a way I could store the toggle event inside the editItems object literal and still have it working as expected?
editItems function looks really odd. I guess you just need to define 2 functions: startEdit and endEdit. And bind them on even and odd clicks using toggle.
var shoppingList = {
// Some code ...
init : function() {
// Bind on edit button click
this.$editButton.toggle(this.startEdit, this.endEdit);
},
startEdit : function() {
$(this).attr('value', 'Finish editing');
shoppingList.$ingrLinks.unbind('click', shoppingList.ingredients) // disable highlighting items
.removeAttr('href');
$('.editme').editable("enable");
$('.editme').editable('http://localhost:8000/edit-ingredient/', {
indicator : 'Saving...',
tooltip : 'Click to edit...',
submit : 'OK',
cancel : 'Cancel'
}),
endEdit: function() {
$(this).attr('value', 'Edit item');
(shoppingList.$ingrLinks).attr('href', '#');
$('.editme').editable("disable");
(shoppingList.$ingrLinks).bind('click', shoppingList.ingredients) // re-enable highlighting items
})
};
$($.proxy(shoppingList, 'init'));

Click on button changes ID value on the button, click on the new ID changes back to original ID with Jquery

I am trying to use a button as a switch. If I click on the button the value and id changes. If I click on the button again it goes back to original value and id.
Original values could look like this:
value="Show all" id="showall"
Changed to this values
value="Standard" id="default"
<script>
$(function () {
$("#showall").click(function () {
$("#showall") // change the Value text to Standard on the button
$("#showall") // Change ID value to default on the button
});
$("#default").click(function () {
$("#default") // change value back to the original which is "Show all"
$("#default") // change ID back to original which is "Showall"
});
</script>
Assuming this button is within some type of <div class="container"></div> where we can handle its event (You could handle it from the body, or document as well, though that's not advised):
$(".container").on("click", "#showall, #default", function(){
var props = this.id === "showall"
? { value:'Standard', id:'default' }
: { value:'Show All', id:'showall' };
$(this).attr( props );
});
Demo: http://jsbin.com/eravoq/2/edit
$("#showall").on('click', function () {
$(this).attr({ 'value': 'Standard', 'id': 'default' });
});
$("#default").on('click', function () {
$(this).attr({ 'value': 'Show all', 'id': 'showall' });
});
why would you change the ID of the button ?
You could do something like that :
$(function () {
$("#switchButton").click(function(){
if($(this).value == "default"){
$(this).value = "Show all";
// do other stuff
}else if($(this).value == "Show all"){
$(this).value = "default";
// do other stuff
}
});
});
$("#showall").on('click', function() {
this.id = this.id=='showall' ? 'default' : 'showall';
this.value = this.value=='Standard' ? 'Show All' : 'Standard';
});
FIDDLE
I know is not exactly what you are asking but if we go an step back in your question I think what you really want is to toggle between two buttons so I think is very much maintainable, understandable, intuitive and a lot of more things to just having two well formed buttons and show/hide then alternatively:
<style>
button#default{
display: none;
}
</style>
​
<button id="showall" value="Show all">Show all</button>
<button id="default" value="Standard">Standard</button>
<script>
function toggleButtons(){
$("button#showall, button#default").toggle();
}
$("button#showall, button#default").click( toggleButtons );
</script>
Check the jsFiddle
You should be using a class toggle instead of changing IDs.
http://jsfiddle.net/JzMnM/
if (that.hasClass('foo')) {
that.removeClass('foo').addClass('bar').val('bar');
} else {
that.removeClass('bar').addClass('foo').val('foo');
}

jQuery: Cannot change style of element after selected

Here is my code. Where you see "alert([...]);", an alert pops up. Why doesn't the CSS style change? The 'click' event doesn't fire either!
resolveSideMenuAddress: function () {
var firstLink = $("#masterHeaderMenu .masterHeaderMenuButton a:first");
function select(link) {
alert('i alert');
link.css({
'color': '#9a4d9e',
'cursor': 'default'
});
alert('color and cursor not changed');
link.click(function () {
alert('click');
return false;
});
}
if (window.location.pathname === firstLink.attr('href')) {
alert('i alert');
select(firstLink);
}
}
I've tried addClass() and can't change the color of the link that way either.
First, you're not actually firing the click event, but rather applying a click handler to the link. It won't fire until you actually click the link. If you want existing click handlers to be run you can try link.click() (without the function). If you want the link to actually be taken, you should simply set the location to the value of the link's href attribute. Second, I'm not sure why the CSS isn't being applied properly. It looks ok to me. I'd suggest using Firefox/Firebug and inspecting the element after the function has run to see what styles are actually in use.
try using $(link) instead of just link
like this:
resolveSideMenuAddress: function () {
var firstLink = $("#masterHeaderMenu .masterHeaderMenuButton a:first");
function select(link) {
alert('i alert');
$(link).css({
'color': '#9a4d9e',
'cursor': 'default'
});
alert('color and cursor not changed');
$(link).click(function () {
alert('click');
return false;
});
}
if (window.location.pathname === firstLink.attr('href')) {
alert('i alert');
select(firstLink);
}
}

Categories

Resources