重写Javascript中的方法

Overriding a Method in Javascript

本文关键字:方法 Javascript 重写      更新时间:2023-09-26

我最近开始使用JsFormValidatorBundle在symfony上验证我的表单。唯一的问题是,我需要用Ajax发送这些表单,不幸的是,由于某种原因,JsFormValidatorBundle强制通过重新加载页面来发送表单。

所以现在我试图覆盖这个函数,它看起来像:

    function FpJsCustomizeMethods() {
    ...
    this.submitForm = function (event) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var element = item.jsFormValidator;
            if (event) {
                event.preventDefault();
            }
            element.validateRecursively();
            if (FpJsFormValidator.ajax.queue) {
                if (event) {
                    event.preventDefault();
                }
                FpJsFormValidator.ajax.callbacks.push(function () {
                    element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                    if (element.isValid()) {
                        item.submit();
                    }
                });
            } else {
                element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                if (element.isValid()) {
                    item.submit();
                }
            }
        });
    };
....
}

如果我去掉item.submit(),它就可以完美地工作。

那么,如何才能推翻这一点呢?

完整脚本

您只需要创建一个新函数并通过其原型扩展父函数。

也许这个代码块可以解释你需要做什么

function Parent() {
    this.a = function() {
        alert("i am here");
    }
    this.submitForm = function() {
        alert("i am wrong one here");
    }
}
function Child () {
    //we need to override function submitForm with right one
    this.submitForm = function() {
        alert("i am right one here");
    }
} 
Child.prototype = new Parent;
var c = new Child();
//other parent methods are still accessible.
c.a();
//method submitForm is overriden with the one we defined
c.submitForm();

请在此处查看操作

正如我所建议的,您实际上不想为了能够通过Ajax而不是默认方式提交表单而覆盖FpJsFormValidator.customizeMethods.submitForm函数。这样做将导致:

  1. 代码复制,因为你将被迫恢复你自己的功能中的所有验证部分

  2. 如果你的解决方案的一部分是去掉item.submit()位,那么你也会丢失任何其他必然会被作为副产品提交的事件。

相反,我只需为该项的提交事件创建一个处理程序,该处理程序将调用event.preventDefault()并执行Ajax请求。当你用jQuery标记你的问题时,类似于:

$("#your_fav_form_selector").submit(function (e) {
    e.preventDefault();
    // fetch form data and send it off with $.ajax etc
});

有两种方法可以做到这一点。据我所知,您想要覆盖的函数不是jQuery函数。我保留了这两个例子,以便您可以决定哪一个适合您的代码。

如果是JavaScript函数(自定义或本机)

首先,我看到了您正在使用的函数,我发现很难覆盖其中的特定部分,所以我重新编写了它,并删除了(或注释掉了)"提交调用",然后我覆盖了该函数。当调用FpJsFormValidator时,以下函数将被调用NewFpJsCustomizeMethods

<script type="text/javascript">
FpJsFormValidator = function() {
    return NewFpJsCustomizeMethods();
}
function NewFpJsCustomizeMethods() {
    this.init = function (options) {
        FpJsFormValidator.each(this, function (item) {
            if (!item.jsFormValidator) {
                item.jsFormValidator = {};
            }
            for (var optName in options) {
                switch (optName) {
                    case 'customEvents':
                        options[optName].apply(item);
                    break;
                    default:
                        item.jsFormValidator[optName] = options[optName];
                    break;
                }
            }
        }, false);
        return this;
    };
    this.validate = function (opts) {
        var isValid = true;
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var method = (opts && true === opts['recursive'])
                ? 'validateRecursively'
                : 'validate';
            var validateUnique = (!opts || false !== opts['findUniqueConstraint']);
            if (validateUnique && item.jsFormValidator.parent) {
                var data = item.jsFormValidator.parent.data;
                if (data['entity'] && data['entity']['constraints']) {
                    for (var i in data['entity']['constraints']) {
                        var constraint = data['entity']['constraints'][i];
                        if (constraint instanceof FpJsFormValidatorBundleFormConstraintUniqueEntity && constraint.fields.indexOf(item.name)) {
                            var owner = item.jsFormValidator.parent;
                            constraint.validate(null, owner);
                        }
                    }
                }
            }
            if (!item.jsFormValidator[method]()) {
                isValid = false;
            }
        });
        return isValid;
    };
    this.showErrors = function (opts) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            item.jsFormValidator.errors[opts['sourceId']] = opts['errors'];
            item.jsFormValidator.showErrors.apply(item, [opts['errors'], opts['sourceId']]);
        });
    };
    this.submitForm = function (event) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var element = item.jsFormValidator;
            if (event) {
                event.preventDefault();
            }
            element.validateRecursively();
            if (FpJsFormValidator.ajax.queue) {
                if (event) {
                    event.preventDefault();
                }
                FpJsFormValidator.ajax.callbacks.push(function () {
                    element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                    if (element.isValid()) {
                        //item.submit();
                    }
                });
            } else {
                element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                if (element.isValid()) {
                    //item.submit();
                }
            }
        });
    };
    this.get = function () {
        var elements = [];
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            elements.push(item.jsFormValidator);
        });
        return elements;
    };
    //noinspection JSUnusedGlobalSymbols
    this.addPrototype = function(name) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var prototype = FpJsFormValidator.preparePrototype(
            FpJsFormValidator.cloneObject(item.jsFormValidator.prototype),
                name,
                item.jsFormValidator.id + '_' + name
            );
            item.jsFormValidator.children[name] = FpJsFormValidator.createElement(prototype);
            item.jsFormValidator.children[name].parent = item.jsFormValidator;
        });
    };
    //noinspection JSUnusedGlobalSymbols
    this.delPrototype = function(name) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            delete (item.jsFormValidator.children[name]);
        });
    };
}
</script>

如果是jQuery函数

首先,我看到了您正在使用的函数,发现很难覆盖其中的特定部分,所以我重新编写了它,并删除了(或注释掉了)"提交调用",然后覆盖了jQuery函数。当调用FpJsFormValidator时,以下函数将被调用NewFpJsCustomizeMethods

这是代码:

<script type="text/javascript">
(function(){
    // Define overriding method
    jQuery.fn.FpJsFormValidator = NewFpJsCustomizeMethods();
})();
function NewFpJsCustomizeMethods() {
    this.init = function (options) {
        FpJsFormValidator.each(this, function (item) {
            if (!item.jsFormValidator) {
                item.jsFormValidator = {};
            }
            for (var optName in options) {
                switch (optName) {
                    case 'customEvents':
                        options[optName].apply(item);
                    break;
                    default:
                        item.jsFormValidator[optName] = options[optName];
                    break;
                }
            }
        }, false);
        return this;
    };
    this.validate = function (opts) {
        var isValid = true;
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var method = (opts && true === opts['recursive'])
                ? 'validateRecursively'
                : 'validate';
            var validateUnique = (!opts || false !== opts['findUniqueConstraint']);
            if (validateUnique && item.jsFormValidator.parent) {
                var data = item.jsFormValidator.parent.data;
                if (data['entity'] && data['entity']['constraints']) {
                    for (var i in data['entity']['constraints']) {
                        var constraint = data['entity']['constraints'][i];
                        if (constraint instanceof FpJsFormValidatorBundleFormConstraintUniqueEntity && constraint.fields.indexOf(item.name)) {
                            var owner = item.jsFormValidator.parent;
                            constraint.validate(null, owner);
                        }
                    }
                }
            }
            if (!item.jsFormValidator[method]()) {
                isValid = false;
            }
        });
        return isValid;
    };
    this.showErrors = function (opts) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            item.jsFormValidator.errors[opts['sourceId']] = opts['errors'];
            item.jsFormValidator.showErrors.apply(item, [opts['errors'], opts['sourceId']]);
        });
    };
    this.submitForm = function (event) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var element = item.jsFormValidator;
            if (event) {
                event.preventDefault();
            }
            element.validateRecursively();
            if (FpJsFormValidator.ajax.queue) {
                if (event) {
                    event.preventDefault();
                }
                FpJsFormValidator.ajax.callbacks.push(function () {
                    element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                    if (element.isValid()) {
                        //item.submit();
                    }
                });
            } else {
                element.onValidate.apply(element.domNode, [FpJsFormValidator.getAllErrors(element, {}), event]);
                if (element.isValid()) {
                    //item.submit();
                }
            }
        });
    };
    this.get = function () {
        var elements = [];
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            elements.push(item.jsFormValidator);
        });
        return elements;
    };
    //noinspection JSUnusedGlobalSymbols
    this.addPrototype = function(name) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            var prototype = FpJsFormValidator.preparePrototype(
            FpJsFormValidator.cloneObject(item.jsFormValidator.prototype),
                name,
                item.jsFormValidator.id + '_' + name
            );
            item.jsFormValidator.children[name] = FpJsFormValidator.createElement(prototype);
            item.jsFormValidator.children[name].parent = item.jsFormValidator;
        });
    };
    //noinspection JSUnusedGlobalSymbols
    this.delPrototype = function(name) {
        //noinspection JSCheckFunctionSignatures
        FpJsFormValidator.each(this, function (item) {
            delete (item.jsFormValidator.children[name]);
        });
    };
}
</script>

其次,如果你想覆盖函数中的一些内容:

<script type="text/javascript">
(function(){
    // Store a reference to the original method.
    var originalMethod = jQuery.fn.FpJsFormValidator;
    // Define overriding method.
    jQuery.fn.FpJsFormValidator = function(){
        // Execute the original method.
        originalMethod.apply( this, arguments );
    }
})();
</script>

注意:

您需要在加载原始函数后编写此代码。