My original question I’ve managed to answer by cobbling other answers together from this site (thank you StackOverflow!) – just posting here to help others wondering.
I have a live event like:
function addValidator(selector, validator) {
// Add the selector and validator to a hash map
$(selector).live('change', validateTag);
}
The table rows are going to vary in number at any time and I don’t want to tightly couple the table creation code with the validation code.
Later another validation function comes along not knowing anything about the first, and I need to avoid that same live selector firing the validateTag function twice, which is going to aggregate all validation messages and present a single UI about a given input.
So – each time someone calls addValidator I need to actually REPLACE the live event handler, or more specifically, expand on its selector (since I’m still calling validateTag, I just need the live handler to cover more ground). I’ll post the answer I came up with below, happy to hear more.
— Update to clarify what I’m doing
I have several pages with dynamic tables that could include any number of rows. I don’t want the validation and the table management code to be tightly coupled. I want to be able to set out inputs in the table rows like:
<input class="required email"/>
And have validation validate it for both the required and email rules onchange(). In code:
Valid.addValidator('input.required', Valid.required);
Valid.addValidator('input.email', Valid.email);
Obviously as rows are added and removed I could keep reapplying the events to the inputs, but that tightly couples the table builder code and the validation code.
Another hack is to just build a single live event like:
$('input, select, textarea').live('change', Valid.validateTag);
And then use a hashmap to look up what exactly applies to this specific tag, but that assumes the only things I’ll ever validate are inputs, selects and textareas, and that the only kind of validation I’ll ever want to do is onchange.
What I really want is to let any kind of validation rule match any tags by selector, without either of the above. The second hack isn’t too bad, but it is a false assumption and is inflexible to custom controls that don’t use one of those 3 basic tags.
Updated after a lot of tinkering and taking suggestions from the other answers here.
validateThis() uses the jQuery .is() method to check each rule for whether this tag is affected by that rule, and if so runs the validator on it.
If you look carefully, there’s also a .find() call in there from an array library I made – it does what you’d expect: Iterate an array until a comparator function you pass in returns true. Then it hands you the item it stopped on, or null.
If people are interested in this library I’m happy to consider going open source with it. The jQuery validation plugin is interesting, but it doesn’t seem to handle the dynamic sets of input I’m using. There’s also some other magic in my library that gets the label for an input based on a ruleset.