I'm pretty new to JQuery, maybe a week's worth of experience, but I'm having a lot of fun so far. One of the things I thought I would give a shot is attempting to implement a custom CMS for my current project. And it's going fairly well. So well in fact, that I thought I would start adding some nifty little features and finalizing it. I mean, why not, I'm learning anyways and what better way than to apply it to an actual project that might benefit from it.
One of the features I thought I'd add would be a dynamic edit toolbar. It uses a delegate to perform event functions on a specific div. Specifically, when the #edit
able section is in focus it will show the toolbar, and on blur it will hide it.
$( '#content' ).on( {
focus : function() {
if( $( this ).prop( 'contentEditable' ) ) {
$( '#toolbar' ).show();
//thinking there might be a way to reuse $( '#toolbar' ) below
//within this pseudo scope
}
},
blur : function() {
$( '#toolbar' ).hide();
}
}, '#edit' );
Pretty neat. I just found this syntax and have been playing with it for a few hours now. Beats having to manually type out a new delegate each time.
This second one does something pretty similar, but it focuses on a single event where the functionality will vary depending on which element is clicked. For instance, if addImage
is clicked I want it to add an image, if bold
I want it to bold, etc... It's a little more complex than that, but this gets the idea across. As you can see, the syntax is different (it's all one function and uses a switch), and no amount of tweaking or searching has helped me to discover if a better way actually exists, or if this is the best already.
$( '#toolbar' ).on( 'click', 'a', function() {
switch( $( this ).parent().prop( 'id' ) ) {
case 'addImage' :
addImage();
break;
case 'bold' :
bold();
break;
case 'italics' :
italics();
break;
case 'underline' :
underline();
break;
}
return false;
} );
I do have an alternative, but I find the one above a little more attractive. Mostly just because there is less indentation, though I guess I could fix that...
$( '#toolbar' ).on( {
click : function() {
//import above switch statement here
}
}, 'a' );
Here are my questions:
- Is there a better way to do this?
- Am I abusing the selectors/delegates?
- Any other general observations or improvements would be appreciated as well.
UPDATE
Thank you Flambino. Your first example reminded me of something we call variable-functions in PHP. In case you are unfamiliar with the term, these are variables that serve as a textual representation of a function and can be used to call that function by adding parenthesis. Example:
function test1() { echo 'test1'; }
function test2() { echo 'test2'; }
$test1 = 'test2';
$test2 = 'test1';
$test1();//variable-function calling test2()
$test2();//variable-function calling test1()
They are not well liked in the PHP community due to their lack of legibility and potential security risk. I know JS isn't going to be as concerned with the security bit, seeing as its front-end and completely visible and manipulable client-side, but lack of legibility looks like it might still be a potential problem. Though, because of the object clarifying this purpose, this does not appear to be as big an issue either. Are these not equally disliked in JS?
Here is my implementation using custom events.
var $toolbar = $( '#toolbar' );
$toolbar.on( 'click', 'a', function() {
var method = $( this ).parent().prop( 'id' );
$toolbar.trigger( method );
return false;
} );
$toolbar.on( {
addImage : function() {
addImage();
},
bold : function() {
bold();
},
//etc...
} );
When implementing custom events I noticed that you are namespacing them with format:
. In my implementation you may have noticed that I neglected to add this. This is because namespacing in this manner would prevent me from using an event object. I played around with this and determined that I could use format_
instead, but this just seemed awkward. Is this violating good practice or something? I can see the benefit, but if they are bound to a specific container, why would namespacing be necessary?
I tried combining the two .on()
blocks, but because the first uses the "a" classifier it limits those events to the anchor tags, which means I would have to explicitly trigger the events like this:
$( '#toolbar > a' ).trigger( method );
Is there a way around this? I'm still toying with this, but haven't found any promising leads yet. I understand from your suggestion about semantics this won't be an issue here anymore, but I've also been applying this to other areas, and in those this looks like its still an issue.
Finally, I am still looking in to your data-*
suggestion. It looks promising, not just here, but in other places as well.
BTW: why are you using .attr()
? Wasn't that deprecated as of 1.6 in favor of .prop()
? Or is there some reason it should be used here over prop()
?