I have just created my first jQuery plugin. I am looking to suggestions on how to improve it, leading to a code optimization.
(function($) {
var plugin_name = 'W.jQuery.FieldEvents';
var name_space = 'wFieldEvents';
var methods = {
init : function(options) {
return this.each(function(){
var field = $(this);
var settings = {
'edit_button' : '',
'submit_button':'',
'error_message':'value not found',
callback:function(){
alert('no call back defined for'+field.attr('id'))
}
};
settings = $.extend(settings, options);
var data = field.data(name_space);
var edit_button = $(settings.edit_button);
var submit_button = $(settings.submit_button);
if (!data) {
$(this).data(name_space, {
submit_button : submit_button,
edit_button :edit_button,
callback:settings.callback,
error_message:settings.error_message
});
}
methods.enable_submit.call(field);
});
},
disable_edit: function(){
return this.each(function(){
var field = $(this);
var data = field.data(name_space);
//alert(data.edit_button.attr('id'));
data.edit_button.attr('disabled','disabled').off('click.'+name_space).addClass('ui-state-disabled');
});
},
enable_submit : function()
{
return this.each(function(){
var field = $(this);
var data = field.data(name_space);
//alert('working');
//alert('enabled submit called for '+field.attr('id'));
methods.disable_edit.call(field);
field.removeAttr('disabled');
data.submit_button.removeAttr('disabled').removeClass('ui-state-disabled');
data.submit_button.on('click.'+name_space,function(){
methods.submit.call(field);
});
field.focus();
});
},
enable_edit: function()
{
return this.each(function(){
var field = $(this);
var data = field.data(name_space);
field.attr('disabled','disabled');
data.edit_button.removeAttr('disabled').removeClass('ui-state-disabled');
data.edit_button.on('click.'+name_space,function(){
methods.enable_submit.call(field);
});
});
},
disable_submit: function(){
return this.each(function(){
var field = $(this);
var data = field.data(name_space);
field.attr('disabled','disabled');
data.submit_button.attr('disabled','disabled').off('click.'+name_space).addClass('ui-state-disabled');
methods.enable_edit.call(field);
});
},
show_error: function(){
return this.each(function(){
var field = $(this);
var data = field.data(name_space);
//alert(data.error_message);
field.focus();
$(dialog_id).html(data.error_message);
$(dialog_id).dialog('open');
});
},
submit:function(){
return this.each(function(){
//alert('submit called');
var field = $(this);
var data = field.data(name_space);
var value = field.val();
if(value != '')
{
methods.disable_submit.call(field);
data.callback();
}
else
{
methods.show_error.call(field);
}
});
},
destroy : function() {
return this.each(function(){
var $this = $(this),
data = $this.data(name_space);
// Namespacing FTW
$(window).W.jQuery.FieldEvents(name_space);
data.wFieldEvents.remove();
$this.removeData(name_space);
});
}
};
$.fn.W_FieldEvents = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on '+plugin_name );
return false;
}
};
})(jQuery);
Usage example:
$(document).ready(function(){
$('#po_number').W_FieldEvents({
'submit_button' : '#po_number_submit',
'edit_button' : '#po_number_edit',
'error_message' : 'PO# number not found',
callback : function(){
alert('submit done');
}
});
});
dialog_id
is not defined anywhere but used inshow_error()
. You also have an implicit global (data
indestroy()
) which neither jshint or jslint caught (I just spotted it by chance). \$\endgroup\$.data()
. Seems pretty straightforward to me (disclaimer: I've never had to make a jQuery plugin, so perhaps someone with more experience has a different opinion). As for the double events, I'd suggest you check for existing data on the elements. If it's there, it's been set up before, and you can merge the existing settings and the passed-in options, instead of merging with the default options. Then calling it twice on the same element won't double the event, but will update the settings. \$\endgroup\$name_space
as well asplugin_name
. Simply use theplugin_name
as the namespace name, and start the supervisor with$.fn[plugin_name] = function(method) {
. @Flambino, with this pattern, you can only store whole-plugin stuff in the closure; no closure within the pattern is scoped to be element-specific so data must be stored in the DOM with.data()
. \$\endgroup\$