views:

2882

answers:

7

I'm using jQuery with the validators plugin. I would like to replace the "required" validator with one of my own. This is easy:

jQuery.validator.addMethod("required", function(value, element, param) {
    return myRequired(value, element, param);
}, jQuery.validator.messages.required);

So far, so good. This works just fine. But what I really want to do is call my function in some cases, and the default validator for the rest. Unfortunately, this turns out to be recursive:

jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods.required(value, element, param);
}, jQuery.validator.messages.required);

I looked at the source code for the validators, and the default implementation of "required" is defined as an anonymous method at jQuery.validator.messages.required. So there is no other (non-anonymous) reference to the function that I can use.

Storing a reference to the function externally before calling addMethod and calling the default validator via that reference makes no difference.

What I really need to do is to be able to copy the default required validator function by value instead of by reference. But after quite a bit of searching, I can't figure out how to do that. Is it possible?

If it's impossible, then I can copy the source for the original function. But that creates a maintenance problem, and I would rather not do that unless there is no "better way."

A: 

Sounds like there's no 'better way'. I guess you could try making a custom required function for your own eg:

jQuery.validator.addMethod("customRequired", function(value, element, param) {
  return myRequired(value, element, param);
}, jQuery.validator.messages.required);

Sounds like you've already tried everything else. Apologies if I misunderstood the question.

sanchothefat
+7  A: 

Storing a reference to the function externally before calling addMethod and calling the default validator via that reference makes no difference.

That's exactly what should work.

jQuery.validator.methods.oldRequired = jQuery.validator.methods.required;

jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods.oldRequired(value, element, param);
}, jQuery.validator.messages.required);

This should work too: (And the problem with this is solved)

var oldRequired = jQuery.validator.methods.required;
jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return oldRequired.call(this, value, element, param);
    // return jQuery.oldRequired.apply(this, arguments);
}, jQuery.validator.messages.required);
Georg
It fixes the recursion (given that, not sure why mine didn't, as I used "var oldRequired" instead of j.v.m.oldrequired" but was otherwise identical, but "this" is now wrong inside oldRequired. I'll work on that, but thanks, I think I'm on the right track now.
Craig Stuntz
crescentfresh's tip fixes "this."
Craig Stuntz
But it's not a nice solution. The best would be to use 'var oldRequired' (no idea why it doesn't work!) and oldRequired.call(jQuery.validator.methods, …, …, …)
Georg
+2  A: 

I think you're just missing a bit of scoping. Try this:

jQuery.validator.methods._required = jQuery.validator.methods.required;
jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods._required.call(this, value, element, param);
}, jQuery.validator.messages.required);
Crescent Fresh
Yes, that fixes the "this" problem. Thanks for that!
Craig Stuntz
A: 

if you want to clone a function , try this :

Function.prototype.clone=function(){
    return eval('['+this.toString()+']')[0];
}
A: 

I need something similar to the clone method provided above. I want to re-use an initialization function, but keep the prototype properties separate.

A: 

Answering the previous post, when I need to share a constructor function, while keeping distinct prototype, I use a wrapper in a new Function :

`

init_from_arg_obj = function () {
    return new Function('init', 'for (var i in init) this[i] = init[i];');
};

constructor_A = init_from_arg_obj();
constructor_A.prototype = {a: 'A'};

constructor_B = init_from_arg_obj();
constructor_B.prototype = {b: 'B'};

`

I run several tests to verify that this does not slow execution on good JS engines.

Max_B
+1  A: 
Function.prototype.clone = function() {
    var fct = this;
    var clone = function() {
        return fct.apply(this, arguments);
    };
    clone.prototype = fct.prototype;
    for (property in fct) {
        if (fct.hasOwnProperty(property) && property !== 'prototype') {
            clone[property] = fct[property];
        }
    }
    return clone;
};

The only bad thing with that is that the prototype isn't cloned so you can't really change it... I'm working on a way to clone any type of objects and I just have RegExp left to do. So I'll probably edit tomorrow and put the entire code (which is kind of long and isn't optimised if you only use it for functions and objects.

And to comment other answers, using eval() is totaly stupid and is way too long and the Function constructor is kind of the same. Literrals are much better. And including JQuery just for that, moreover if it doesn't work properly (and I don't think it does) isn't the brightest thing you can do.

xavierm02