How can I reuse a variable in a different scope? - javascript

I am trying to figure out how I can reuse a variable within a function, right now I have to put it in each scope for it to work.
Say I have an jQuery Event handler:
$('.button').on('click', function() {
var btn = $(this).data('button');
$(this).addClass(btn+'-activate');
}).on('mouseup', function() {
var btn = $(this).data('button');
$(this).removeClass( btn+'-activate');
}).on('mouseleave', function() {
var btn = $(this).data('button');
$(this).removeClass( btn+'-activate');
}
How can I reuse the variable 'btn'? When I put it in the parent scope, it doesn't recognize $(this) anymore

The other answers have a bit of redundancy in them. Here is how I usually handle events that are related and have common variables:
$('.button').on('click mouseup mouseleave', function(event) {
var btn = $(this).data('button');
switch(event.type) {
case 'click': {
$(this).addClass(btn+'-activate');
break;
}
case 'mouseup':
case 'mouseout':
case 'mouseleave': {
$(this).removeClass(btn+'-activate');
break;
}
}
});
Listen to multiple events and use a switch statement to determine which event was called.

You can just iterate over the buttons, set the variable for each one and then use the variable inside the event handlers.
$('.button').each(function() {
var btn = $(this).data('button');
$(this).on('click', function() {
$(this).addClass(btn+'-activate');
}).on('mouseup mouseleave', function() {
$(this).removeClass( btn+'-activate');
});
});
But of course this is not exactly the same as your code. Here we are setting the value of btn at the time the handlers are attached while, in the code of the question, btn is set at the time the handlers are called. Therefore this is only a valid alternative if the value of .data('button') is not meant to change.

There's no special advantage to using a variable. You can pass a function to .removeClass() and .addClass() thereby removing the need to use a variable:
$(function() {
$('.button').on('click', function() {
$(this).addClass( function() {
return $(this).data('button') + '-activate';
});
}).on('mouseup mouseleave', function() {
$(this).removeClass( function() {
return $(this).data('button') + '-activate';
});
});
});
$(function() {
$('.button').on('click', function() {
$(this).addClass( function() {
return $(this).data('button') + '-activate';
});
}).on('mouseup mouseleave', function() {
$(this).removeClass( function() {
return $(this).data('button') + '-activate';
});
});
});
.one-activate {
background-color:black;
color:white;
}
.two-activate {
background-color:black;
color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="button" data-button="one">Man</button><br/>
<button class="button" data-button="two">Woman</button><br/>
BONUS:
As you can see the functions passed to .removeClass() and .addClass() are exactly identical. We could write a jQuery custom method and use it in place of the functions as follows:
$(function() {
$('.button').on('click', function() {
$(this).addClass( $(this).btnActivate() );
})
.on('mouseup mouseleave', function() {
$(this).removeClass( $(this).btnActivate() );
});
});
$.fn.btnActivate = function() {
return this.data('button') + '-activate';
};
$(function() {
$('.button').on('click', function() {
$(this).addClass( $(this).btnActivate() );
})
.on('mouseup mouseleave', function() {
$(this).removeClass( $(this).btnActivate() );
});
});
$.fn.btnActivate = function() {
return this.data('button') + '-activate';
};
.one-activate {
background-color:black;
color:white;
}
.two-activate {
background-color:black;
color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="button" data-button="one">Man</button><br/><br/>
<button class="button" data-button="two">Woman</button><br/>

Related

How to combine two jQuery functions

Good Morning.
I want to combine my jQuery functions into one.
$('body').on('click', '.toggle2', function() {
console.log(123);
$('body').find('.dateshow').toggleClass('show');
});
$('body').on('click', '.toogle3', function() {
$('body').find('.autorshow').toggleClass('show');
});
$('body').on('click', '.toogle4', function() {
console.log(123);
$('body').find('.starshow').toggleClass('show');
});
Many thanks in advance
If you change all of your toggle links to have the following markup:
click
click
click
Then you can add a more generic handler such as:
$('.toggle').on('click', function() {
var targetSelector = $(this).attr('data-toggle');
$('.' + targetSelector).toggleClass('show');
});
Codepen: http://codepen.io/anon/pen/aBKJEb
When a callback is called jQuery will pass in an event object. You can check the target of the event and process as needed.
$('body').on('click', '.toggle2, .toogle3, .toogle4', function(e) {
var $target = jQuery(e.target),
$targetObject;
if($target.hasClass('toggle2')) {
$targetObject = jQuery('body').find('.dateshow');
}
if($target.hasClass('toogle3') {
$targetObject = jQuery('body').find('.autorshow');
}
if($target.hasClass('toogle4') {
$targetObject = jQuery('body').find('.starshow');
}
$targetObject.toggleClass('show');
});
$('body').on('click', '.toggle2,.toogle3,.toogle4', function() {
var mapper = {
'toggle2': { cls: '.dateshow', console:true },
'toggle3': { cls: '.autorshow', console:false },
'toggle4': { cls: '.starshow', console:true }
};
this.classList.forEach(function(cls) {
var obj = mapper[cls];
if(obj) {
obj.console && console.log(123);
$('body').find(obj.cls).toggleClass('show');
}
});
});

Getting localStorage and adding class to divs

I have a question that is quite confusing.
Everytime I check a "checkbox", it gets the closest "div" and add the class "hilight" and "marked" and set an Item to LocalStorage called "marking".
When I switch from div 1 to 2, I remove the class "hilight", but i keep the class "marked".
I'm trying to get the LocalStorage, and add class "hilight" again to divs that has "marked"
JS Fiddle: http://jsfiddle.net/b4KgV/
HTML
1
2
<button class="1st">show 1st</button>
<button class="2nd">show 2nd</button>
JS
localStorage.clear();
$(document).on('click', ':checkbox', function () {
if ($(this).is(':checked')) {
$(this).closest("div").addClass('hilight marked');
localStorage.setItem("marking","yes");
}
else {
$(this).closest("div").removeClass('hilight marked');
}
});
$(".1st").on('click', function() {
$(".second").css('display','none');
$(".second").removeClass('hilight');
$(".first").css('display','block');
});
$(".2nd").on('click', function() {
$(".first").css('display','none');
$(".first").removeClass('hilight');
$(".second").css('display','block');
});
if (localStorage.getItem("marking")) {
$(".marked").closest("div").addClass('hilight');
};
Thx.
Localstorage goes by key:value as you know, I tried to keep them separate.
Try this fiddle
http://jsfiddle.net/b4KgV/11/
$(document).on('click', ':checkbox', function () {
var div = $(this).closest("div").attr("id")
if ($(this).is(':checked')) {
$(this).closest("div").addClass('hilight marked');
localStorage.setItem(div, true);
} else {
$(this).closest("div").removeClass('hilight marked');
localStorage.setItem(div, false);
}
});
$(".1st").on('click', function () {
console.log("test")
if (localStorage.getItem("firstDiv") == "true") {
$(".first").closest("div").addClass('hilight');
};
$(".second").css('display', 'none');
$(".second").removeClass('hilight');
$(".first").css('display', 'block');
});

On/off click event on alternating tabs

$('#filter').on('click', function(){
$('#sort').off('click');
console.log($(this));
});
$('#sort').on('click', function(){
$('#filter').off('click');
console.log($(this))
});
$('.close').on('click', function () {
console.log($(this));
$('#sort').on('click');
$('#filter').on('click');
});
Why doesnt the div .close give back the on method to the divs above if they have the same selector id?
EDIT: For clarity, I'm wanting to temporarily remove the on event on whichever of the two elements wasn't clicked (#filter or #sort). Then clicking '.close' will return the said element back to having the on method again.
The off() does not work the way you think. It actually removes the event handlers (callback functions), not just hides them, so you cannot restore them with a simple on(), they are not stored any longer by the element after the off(), you have to add them again. It is not easy to track whether an event handler is added, so I suggest another approach.
var sort = true;
var filter = true;
$('#filter').on('click', function(){
if (!filter)
return;
sort = false;
console.log($(this));
});
$('#sort').on('click', function(){
if (!sort)
return;
filter = false;
console.log($(this))
});
$('.close').on('click', function () {
console.log($(this));
sort = true;
filter = true;
});
Another approach to use toggle() and combine it with the on() and off() functions. Hmm I found that jquery toggle() is not loosely coupled to dom elements, so you cannot do this with that. You have to create your own implementation, for example something like this:
function toggle(options) {
var currentValue = !!options.value;
return function (value){
if (value === undefined)
value = !currentValue;
if (value != currentValue)
if (value) {
currentValue = true;
options.on();
}
else {
currentValue = false;
options.off();
}
};
}
With this toggle implementation your code will be the following:
var switches = {
sort: toggle({
on: function (){
$('#sort').on('click', function(){
switches.filter(false);
console.log($(this))
});
},
off: function (){
$('#sort').off('click');
}
}),
filter: toggle({
on: function (){
$('#filter').on('click', function(){
switches.sort(false);
console.log($(this));
});
},
off: function (){
$('#filter').off('click');
}
})
};
$('.close').on('click', function () {
console.log($(this));
switches.sort(true);
switches.filter(true);
});
switches.sort(true);
switches.filter(true);
You can try with:
$('#filter:not(.off)').on('click', function(){
$('#sort').addClass('off');
console.log($(this));
});
$('#sort:not(.off)').on('click', function(){
$('#filter').addClass('off');
console.log($(this))
});
$('.close').on('click', function(){
$('#sort').removeClass('off');
$('#filter').removeClass('off');
console.log($(this));
});
I'm assuming that in your block of codeā€¦
$('.close').on('click', function () {
console.log($(this));
$('#sort').on('click');
$('#filter').on('click');
});
You want to click #sort and #filter. To do such, you'll need to do the following:
$('.close').on('click', function () {
console.log($(this));
$('#sort').click();
$('#filter').click();
});
Even so, it would probably be better to wrap the other event handlers in a function and call them like such:
$('.close').on('click', function () {
console.log($(this));
sortClickFunction();
filterClickFunction();
});
This will do anything: $('#sort').on('click');
You need to call: $('#sort').trigger('click');

Is it possible to bind multiple functions to multiple delegation targets in one place?

As it is possible to define multiple event handlers in one single function in jQuery like this:
$(document).on({
'event1': function() {
//do stuff on event1
},
'event2': function() {
//do stuff on event2
},
'event3': function() {
//do stuff on event3
},
//...
});
Then again we can do this:
$(document).on('click', '.clickedElement', function() {
//do stuff when $('.clickedElement') is clicked
});
I was wondering if it is also possible to do something like this (the following code does not work, it's just for illustration):
$(document).on('click', {
'.clickedElement1', function() {
//do stuff when $('.clickedElement1') is clicked
},
'.clickedElement2', function() {
//do stuff when $('.clickedElement2') is clicked
},
//... and so on
});
This code gives me an error complaining about the "," after '.clickedElementX'. I also tried it like this:
$(document).on('click', {
'.clickedElement1': function() {
//do stuff when $('.clickedElement1') is clicked
},
//... and so on
});
Then I don't have the error but also the function is not executed. Is there a way to collect all the click handlers in one place like this or would I have to always do it like this:
$(document).on('click', '.clickedElement1', function() {
//do stuff when $('.clickedElement1') is clicked
});
$(document).on('click', '.clickedElement2', function() {
//do stuff when $('.clickedElement2') is clicked
});
//... and so on
You can chain :
$(document).on({
click: function() {
//click on #test1
},
blur: function() {
//blur for #test1
}
}, '#test1').on({
click: function() {
//click for #test2
}
}, '#test2');
FIDDLE
Short answer: no, you have to bind them all separately.
Long answer: You can create an "infrastructure" for your site and have all events in one place. e.g.
var App = function(){
// business logic
return {
Settings: { ... },
Events: {
'event1': function(){
},
'event2': function(){
},
'event3': function(){
}
}
}
}();
Then wiring it up involves:
$(document).on(App.Events);
Then internally you can add then new bindings to your App object but still remains wired up in only one place (as far as jQuery is concerned). You could then make some kind of subscriber model within App (e.g. App.Subscribe('click', function(){ ... })) and each new subscription still is only wired through the single .on() binding.
but, IMHO, this is a lot of overhead with very little pay-off.
$(document).on('click' , function(e){
if($(e.target).hasClass("some-class")){
//do stuff when .some-class is clicked
}
if($(e.target).hasClass("some-other-class")){
//do stuff when .some-other-class is clicked
}
});
you can choose any some-class you want
It can be easily done, really:
$(document).ready(function()
{
$(this).on('click', '.one, .two',function()
{
if ($(this).hasClass('one'))
{//code for handler on .one selector
console.log('one');
}
else
{//code for handler on .two selector
console.log('two');
}
console.log(this);//code for both
});
});
If multiple events is what you're after:
$(document).ready(function()
{
$(this).on('click focus', '.one, .two',function()
{
if (event.which === 'click')
{
if ($(this).hasClass('one'))
{
console.log('one');
}
else
{
console.log('two');
}
}
else
{
console.log('focus event fired');
}
console.log(this);
});
});
Play around with this: here's a fiddle
documentation on event
jQuery's on, which is used here as though it were delegate
you can use a helper function:
function oneplace(all){
for (var query in all){
$(query).on('click', all[query]);
}
}
and then call:
oneplace(
{'#ele1':function(){
alert('first function');
},
'#ele2':function(){
alert('second function');
}});
jsfiddle here: http://jsfiddle.net/5zwkf/

How can I trigger a 'focusout' after I click on an element?

I have the following markup:
<select style="display:none">
<option value='1'>1</option>
<option vlaue='2'>2</option>
</select>
<input type="text" id="comboBox" />
<ul id="comboBoxData" style="display:none">
<li id='1'>1</li>
<li id='2'>2</li>
</ul>
and the following JQuery code:
$(document).ready(function() {
$('select').each(function() {
var parent = this;
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$(parent).val(value);
$('#comboBox').val(value);
});
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
$('#comboBox').bind('focusout', function () {
$('#comboBoxData').hide();
});
});
When I click on one of the LI's the 'comboBoxData' element disappears before the click trigger happens. Is there a way around this or an alternate event that I can use instead to have the same effect as a focusout?
Put mouseenter and mouseleave events and change the value of a global variable say isOver.
$('select').each(function() {
var parent = this;
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$(parent).val(value);
$('#comboBox').val(value);
$('#comboBoxData').hide();
});
});
$('#comboBoxData').mouseover(function(){
isOver = true;
}).mouseleave(function(){
isOver = false;
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
$('#comboBox').bind('focusout', function () {
if(!isOver){
$('#comboBoxData').hide();
}
});
You do not require this:
$('#comboBox').bind('focusout', function () {
$('#comboBoxData').hide();
});
instead use this inside $('#comboBoxData').on('click', 'li', function() {
if you are fine with plugin , you could just use this way:
$('#menu').bind('clickoutside', function (event) {
$(this).hide();
});
You can get that plugin here
Also, I have changed the code without using the plugin:
Please check the updated answer:
DEMO
try with blur() function
$('#comboBox').blur(function () {
$('#comboBoxData').hide();
});
The blur event is sent to an element when it loses focus.
from http://api.jquery.com/blur/
Not exactly elegant but it works.
$("body").click(function(event){
if(!$(event.target).is("#comboBoxData") && !$(event.target).is("#comboBox") ){
$("#comboBoxData").hide(); }
});
$(document).ready(function() {
$('select').each(function() {
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$('#comboBox').val(value);
$('#comboBoxData').hide();
});
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
});

Categories

Resources