I’m building a simple jQuery plugin called magicForm (How ridiculous is this?). Now face to a problem that I think I’m not figuring out properly.
My plugin is supposed to be applied on a container element, that will show each of its inputs one by one as user fills them. That’s not the exact purpose of my problem.
Each time I initialize the container, I declare an event click callback. Let me show an example.
(function($){
var methods = {
init: function(options){
return this.each(function(){
var form, inputs;
var settings = {
debug: false
};
settings = $.extend(settings, options);
form = $(this);
$('a.submit', form).on('click', function(event){
if (settings.submitCallback) {
settings.submitCallback.call(form, inputs);
}
return false;
});
});
},
reset: function() {
}
}
$.fn.magicForm = function(method) {
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.' );
}
};
})($);
I’m focusing on a specific part of this code :
$('a.submit', form).on('click', function(event){
if (settings.submitCallback) {
settings.submitCallback.call(form, inputs);
}
return false;
});
Because each time the init method is called, that poor callback is registered.
I was experiencing this painfully, when I invoked my plugin on an element nested in a twitter bootstrap ‘tab’, nested itself in a bootstrap modal :
I was calling init each time the event ‘shown’ of my bootstrap modal was triggered.
So, this is how I fixed it in my init method :
// Prevent callback cumulation
if (!$(this).data('form_initialized')) {
$('a.submit', form).on('click', function(event){
if (settings.submitCallback) {
settings.submitCallback.call(form, inputs);
}
return false;
});
$(this).data('form_initialized', true);
}
And I’m far from feeling sure about this.
Thank your for your time !
Many jquery plugins use
datato know if their plugins were initialized. Most often, they use the name of their own plugin as a part (or in whole) as the data. For example:$(this).data('magicForm')So your approach of using that to signal is not a bad one.
However, you have two other options:
1) Pull the event handler out so the handler is a single instance. Above your methods, do
var fnOnSubmit = function() { ... }Then you can simply ensure proper binding by calling$('a.submit', form).unbind('click', fnOnSubmit)before rebinding it the way you are already doing it.2) Another option is to use event namespaces.
$('a.submit', form).unbind('click.magicForm');then rebinding it with.on('click.magicForm')This namespace approach ensures that when you unbind it only unbinds in the context of your namespace magicForm, thus leaving all other click events (e.g. from other plugins) intact.I hope this helps.