Question

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."

Was it helpful?

Solution

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);

OTHER TIPS

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.

Here is an updated answer

var newFunc = oldFunc.bind({}); //clones the function with '{}' acting as it's new 'this' parameter

However .bind is a new feature of JavaScript there is however a workaround from Mdn

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Additionally it does not clone the function additional properties.

Note: As @gsnedder pointed out : the bound statement, "this" argument u supplied (blank {} above). Will persist for any future calls of the function, regardless of over-riding via the apply()/call() functions.

This can be used both to your advantage, or disadvantage depending on how you deal with it.

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);

(this should only be a comment for Can I copy/clone a function in JavaScript? ... unfortunately with rep < 50 can only post)

Function.prototype.clone=function(){
    return eval( '('+this.toString()+')' );
}

suffices, or even

Object.prototype.clone=function(){
    return eval( '('+this.toString()+')' );
}

thoughts on efficiency:

  • human efficiency is far more important than squandering human resources to optimize or improve a machine's "life"
  • computers and automated systems are supposed to reduce human effort not increase it
  • computational overhead must severely impact a result's palatability for human consumption, by many many people, to justify investing effort in optimizing code that often becomes more obscure, arcane and so esoteric that it can no longer be understood by a stable of programmers after hours of trying to "comprehend" the logic

on cloning: this question can be quite rhetorical

  • what does it mean to "clone" a javascript object? especially in the context of recursive function theory
    • a common theme to rationalize cloning is that it isolates and "protects" an originator from its doppelgänger changes
    • if a = new Object(); b = new Object(); are a and b clones? how about o = Object; a = new o(); b = new o();
  • is it really required?
  • where does cloning stop? are the prototypical attributes to be isolated also so a cloned object's change of these does not affect instances not associated with the cloned object? in which case cloning must go all the way up the prototypical chain to the primitive constructors which themselves would need to be somehow cloned and isolated (one trick in a browser is to open a new window and repopulate it with the caveat that opener . etc. can still leak cross-effects)

if you want to clone a function , try this :

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

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top