Say when a checkbox is checked/unchecked, I want specific behavior to occur.
Now if there are multiple points in my code where I set a checkbox as checked/unchecked, I have to run through the same logic ever time.
What is a way I can encapsulate the logic that occurs when a checkbox is checked, and just re-use that logic?
My guess is that you're currently binding click event handlers like this:
$('some-selector').click(function (event)
{
// do fancy stuff here
});
To encapsulate that logic, you just need to switch from using an anonymous function, to a function that you can reuse, like this:
function handleClicks(event)
{
// do fancy stuff here
}
$('some-selector').click(handleClicks);
$('some-other-selector').click(handleClicks);
How's that?
I might also take a guess at the fact that the logic you're writing and rewriting is to wire a "check-all" sort of checkbox to a group of checkboxes. I wrote a jQuery plugin recently to handle exactly this sort of thing.
I never got around to uploading it properly to GitHub - here's the gist of it. Let me know if you'd like to actually use it, and I can explain its usage - it's pretty darn simple.
Just extending what 'Bears will eat you' said about using non-anonymous functions, you should all so integrate your own function library to jquery:
Create your functions like so
$.fn.handleClicks = function (){
$(this).click(function(event){
alert('Click');
return false
})
}
Then you can use them like so, makes things a little more neater and a little lesser code. IMO;
$('a').handleClicks();
Related
I wrote some code, but I am pretty sure, that this could be shorter but my brain just stopped working and therefore I want to ask you about some tipps.
The problem is, that there are kind of redundancies in the code and like I said, I am pretty sure, that some kind of loop or something could handle this problem.
This piece of code is, like the name of the function, for toggling two different contents. This is for simulating a header with two tabs and therefore to present different content, when one of the two tabs are clicked.
function toggleContent() {
if(!firstTab.classList.contains("active")) {
firstTab.classList.add("active");
secondTab.classList.remove("active");
firstContent.classList.add("visible");
secondContent.classList.remove("visible");
} else {
secondTab.classList.add("active");
firstTab.classList.remove("active");
secondContent.classList.add("visible");
firstContent.classList.remove("visible");
}
}
classList has a toggle method with a second argument that may help
function toggleContent() {
var isFirstTabActive = firstTab.classList.contains("active");
firstTab.classList.toggle("active", !isFirstTabActive);
secondTab.classList.toggle("active", isFirstTabActive);
firstContent.classList.toggle("visible", !isFirstTabActive);
secondContent.classList.toggle("visible", isFirstTabActive);
}
This doesn't take into consideration the possibility of even shorter code - however, as the HTML is a mystery, this will do
I was just wondering which is the correct or most efficient way of navigating through the Dom using variables.
For example, can I concatenate selectors
var $container = '.my-container';
$($container).addClass('hidden');
$($container + ' .button').on('click', function(){
//something here
});
or should I use the jQuery traversal functions
var $container = $('.my-container');
$container.addClass('hidden');
$container.children('.button').on('click', function(){
//something here
});
Is there a different approach, is one best, or can you use them at different times?
The $ is usually used only when working with an actual jquery object. You generally shouldn't prefix anything with that unless it's really something from jquery.
Beyond that little bit though, performance-wise, your second bit of code is going to be faster. I made an example jsperf here: http://jsperf.com/test-jquery-select
The reason the second bit of code is faster is because (if I remember correctly) jquery caches the selection, and then any actions performed on that selection are scoped. When you use .find (which is really what you meant in your code, not .children), instead of trying to find elements through the entire document, it only tries to find them within the scope of whatever my-container is.
The time when you wouldn't want to use the second pattern is when you expect the dom to change frequently. Using a previous selection of items, while efficient, is potentially a problem if more buttons are added or removed. Granted, this isn't a problem if you're simply chaining up a few actions on an item, then discarding the selection anyway.
Besides all of that, who really wants to continuously type $(...). It's awkward.
so I have this idea I'm working on over on Codepen. I've got it working as it is but before I go and add more clickable areas I've realized a massive need to refactor and DRY things up. So far it works but it's ugly as hell and would involve a massive amount of repeated code.
So I'm trying to replace the many $(.class).click(function() { ... }); functions with a switch statement that uses $(this) to populate a single .click function instead. But I'm lost.
You can see everything here and edit it also: http://codepen.io/lukewatts/pen/ubtmI
I feel like I'm close but I've hit a wall. The top commented out part is the DRY attempt while what is uncommented for now is the working version. Click the min, off, max words or the LEDs to see it work.
Thank you very much in advance for any advise on this. PHP is my main language to be honest.
P.S. I had leds.click(function() { ... }) and I replaced it with leds.on(function() { ... }) but still nothing.
I understand what you are trying to do, but that not how the jQuery object works. In order to check for the object to match a selector, you will have to use .is().
As such, you will not be able to use a switch, but you will have to use a serie of chained ifs to achieve the goal the way you are trying, such as
if ( $this.is('.led[data-level="one"]') )
var led = $('p.min a');
var level = "one";
I have updated your CodePen example to work in this way: Codepen
As I mentioned in my comment to the question, though, I am not making any code review here, just fixing what didn't work for you. I am not sure this is actually a better approach than your messy original one, to be entirely honest.
The refactored version looks good for me. If you don't like to use addClass and removeClass you may directly change the class property of the element:
indicator.attr("class", "one on");
The reason your switch statement doesn't work is because every time you create a jQuery object, it gets an Id, so when the switch tries to compare $this to a selector like $(p.min a), they won't be equal. However, if you used multiple if statements with $.is, you could compare:
$this = $(this)
if($this.is('p.min a')) {
// do work
} else if($this.is('p.max a')) {
// do work
}
I wouldn't, however, recommend this approach. For more complex pages, I'd recommend a binding framework like Knockout.js. For something small, you're adding a lot of complexity. For clarity: If this becomes part of a larger control set or system, a binding framework would be useful. For the control as-is, both a binding framework and the OP's current approach are overkill.
You may want to look at event delegation, I find it very helpful to keeping things DRY. Clicks will bubble up the DOM tree to higher elements, and you can register your handler on an ancestral element. This is actually ideal, as you only bind a single handler to a single element, instead of binding to multiple elements and thus you realize a performance benefit in addition to cleaner code.
First thing, wrap all your .led elements in a <div id="leds">:
<div id="leds">
</div>
Now create your handler:
$('#leds').bind('click', function(e){
var target = e.target;
var $target = $(target);
//do interesting stuff
if (target.nodeName === 'A') {
var level = $target.data('level');
if(level = 'one'){
//do more interesting stuff
}
}
}
});
I find myself doing different things to the same jQuery object a lot.
So instead of doing something like this:
var thing = $("pile_o_selectors");
thing.blah;
thing.blah_2;
//...
thing.blah_n;
or even worse
$("selectors").blah;
$("selectors").blah_2;
//...
$("selectors").blah_n;
So, I made a little jQuery plugin to let me do this:
$("selectors").do(function(){
this.blah;
this.blah_2;
this.blah_n;
});
Is there a built in jQuery function that already does this? Or even a plugin that already exists and is tested and mature so I don't have to put effort into making sure mine works in all cases? I tried searching the web a bit, but I don't even know what to call it.
Not 100% sure what those 'things' you want to do are, but can they simply be chained?
http://www.w3schools.com/jquery/jquery_chaining.asp
i.e. $("#p1").css("color","red").slideUp(2000).slideDown(2000);
You can just chain them. For example:
$('selector')
.hide()
.text("Hello, world!")
.fadeIn();
This works for most methods that have nothing obvious to return; in that case, they return the jQuery object again, making it possible. However, if they need to return something, then they can't return the jQuery object, and you cannot chain any further.
I'm populating a list by cloning elements into it. Then I change attrs to make each item unique. They need to call a function on click, so I'm wondering if it's more efficient to use new_element.click(func); or new_element.attr('onlick','func();');
new_element.attr('onclick','func();');
Is:
inefficient (needlessly creating a new inline function from a string, that does nothing except call func and lose the this reference);
aggravating to put any complex code in, since it all has to be JS string escaped;
broken in IE, due to bugs in setAttribute.
Avoid. click()/bind('click') is there for a reason.
onclick has a number of limitations, including cluttering the DOM and only allowing one function at a time. So you should use click. See Quirks Mode for more information.
Directly referencing the function will be more efficient than having to interpret a string.
The lowest touch way of doing this, however, is this way:
$(links_selector).live('click', func);
links_selector will presumably be something like ul.listClass a.actionClass. This will not require anything to be done when new list elements get added.
Since you are using jQuery then make it this way
new_element.click(function(){
// your code
});
or you can bind the click event handler like
new_element.bind("click", function(){
// your code
});
Any difference in performance between the two is most likely going to be negligible. You should use the one that reads better, and that's element.click. (Plus, onclick has many disadvantages, as #Matthew Flaschen mentioned.)