I started working on a jQuery port for this Form Dependency Manager script. It works fine, and I added a few extra options too.
The problem is speed. If you create dependencies between 20+ form elements on a page you get the PC to run really slow. Firefox is throwing that "script is too slow" message. This is probably because of the heavy FOR loops.
Do you guys have any suggestions on how could this be improved, or maybe new ideas on how to implement this kind of functionality?
(function($){
$.fn.setupDependencies = function(options){
var defaults = {
attribute : 'rules', // the field attribute which contains the rules (use 'rel' for w3c valid code)
disable_only : true, // if true it will disable fields + label, otherwise it will also hide them
clear_inactive : false, // clears input values from hidden/disabled fields
identify_by : 'name', // attribute used to identify dependencies (ie. DEPENDS ON [identify_by] BEING ...)
condition_separator : ' AND ', // rules...
possibility_separator : ' OR ',
name_value_separator : ' BEING ',
depends : 'DEPENDS ON ',
conflicts : 'CONFLICTS WITH ',
empty : 'EMPTY'
},
settings = $.extend({}, defaults, options),
matches = this,
valueMatches = function(e, v){
return (e.val() == v || (e.is(':radio') && e.filter(':checked').val() == v));
},
// show or enable
show = function(e){
$('label[for="' + e.attr('id') + '"]').removeClass('disabled');
e.removeAttr('disabled');
if(!settings.disable_only){
e.show();
$('label[for="' + e.attr('id') + '"]').show();
}
return true;
},
// hide or disable
hide = function(e){
$('label[for="' + e.attr('id') + '"]').addClass('disabled');
e.attr('disabled', 'disabled');
if(!settings.disable_only){
e.hide();
$('label[for="' + e.attr('id') + '"]').hide();
}
if(settings.clear_inactive == true && !e.is(':submit')) // ignore submit buttons
if(e.is(':checkbox,:radio')) e.removeAttr('checked'); else e.val('');
return true;
};
return this.bind('change input', function(){ // note: input event not working in IE <= 8, obviously
var j, k, f, n, isHidden, dep;
matches.each(function(){
isHidden = false;
dep = $(this).attr(settings.attribute);
if(typeof dep !== 'undefined' && dep !== false)
for(j = 0, f = dep.split(settings.condition_separator); j < f.length; ++j)
if(f[j].indexOf(settings.depends) === 0){
for(k = 0, g = f[j].substr(settings.depends.length).split(settings.possibility_separator); k < g.length; ++k)
if(g[k].indexOf(settings.name_value_separator) === -1){
if(matches.filter('[' + settings.identify_by + '="' + g[k] + '"]').is(':checked')) break; else if(k + 1 == g.length) isHidden = hide($(this));
}else{
n = g[k].split(settings.name_value_separator);
if(valueMatches(matches.filter('[' + settings.identify_by+'="' + n[0] + '"]'), n[1])) break; else if(k + 1 == g.length) isHidden = hide($(this));
}
}else if(f[j].indexOf(settings.conflicts) === 0){
if(f[j].indexOf(settings.name_value_separator) === -1){
if(matches.filter('[' + settings.identify_by + '="' + f[j].substr(settings.conflicts.length) + '"]').is(':checked')){
isHidden = hide($(this));
break;
}
}else{
n = f[j].substr(settings.conflicts.length).split(settings.name_value_separator);
if(valueMatches(matches.filter('[' + settings.identify_by + '="' + n[0] + '"]'), n[1])){
isHidden = hide($(this));
break;
}
}
};
if(!isHidden) show($(this));
});
return true;
}).change();
};
})(jQuery);
Note that my version uses a non-standard attribute for the rules by default (rules
) instead of class
like in the original script...
class
. At least you should use a HTML5data-
attribute. \$\endgroup\$