javascript OOP不工作:未捕获TypeError:对象不是函数

Hai*_*ood 5 javascript oop jquery function

好吧,所以背景故事是我们在页面上有一堆相同的(函数内)表单来为产品添加变体,表单由三个主要部分组成.

属性编辑器

在此输入图像描述
该组件允许用户向产品添加属性.每个属性都有一个visibility status,一个attribute key,一个attribute value和一个delete button一起形成一行.

该组件还有一个Add Attribute按钮,单击该按钮会在列表底部添加一个新行.

每个attribute key选择列表都有一个new attribute选项,在选择时启动一个带有表单的模态对话框以输入新的属性名称,然后该表单通过AJAX提交并返回一个ID,然后将新选项附加到attribute key页面上的每个选项以允许它被选中.

当在组件的实例中选择了一个键时,组中的所有其他attribute key选择都会禁用该选项以防止重复的属性.

属性编辑器作为下面主表单的一部分提交.


主要表格

在此输入图像描述
该组件由变体的一般描述字段组成.表单通过AJAX提交,并附加了jQuery Validation Engine以进行表单验证.

因为我们使用属性编辑器动态添加新输入,所以我们必须不断分离并重新附加验证引擎.


警报系统

在此输入图像描述
此组件按表单处理在表单上显示/隐藏错误/成功/状态消息.


问题

现在还有一些非常相似的形式,但是在几个事件处理程序上有轻微的变化,所以我想创建代码,这样我就可以随意替换它的一些部分,而不必复制整个代码.

所以在按照这个问题的提示后,我最终得到了下面的代码,但是我收到了错误:Uncaught TypeError: object is not a function这是在这一行:var variantAlert = new VariantAlert(form);我相信是因为我没有返回任何东西,但我不知道应该返回什么获取代码来做我想要的!

精简版

$(function () {

    $("form.variant-form").each(function (i, form) {
        var variantAlert = new VariantAlert(form);

        var variantForm = new VariantForm(form, variantAlert);
        variantForm.init();

        var attributeEditor = new AttributeEditor(form, variantForm);
        attributeEditor.init();
    });
});

var AttributeEditor = (function (form, formSetup) {

    form = $('form');

    var someVar = 123;

    var init = function () {     
        someEventHandler();
    };

    var someEventHandler = function () {
        $('.selector', form).on('some event', function (e) {
            form.css('background-color', '#f00');
        });
    };

    return AttributeEditor;
})();

var VariantForm = (function (form, variantAlert) {
    form = $('form');

    var init = function () {
        anotherEventHandler();
    };

    var anotherEventHandler = function () {
        $('.anotherSelector', form).on('another event', function () {
            form.doStuff();
        });
    };
})();

var VariantAlert = (function (form) {
    var timer;

    form = $('form');

    var message = function (type, message) {
        doMoreStuff(type, message);
    }


})();
Run Code Online (Sandbox Code Playgroud)

完整版本

$(function () {

    /*********************************
     * Loop over each variant and setup
     * the attribute editor and form
     *********************************/
    $("form.variant-form").each(function (i, form) {
        var variantAlert = new VariantAlert(form);

        var variantForm = new VariantForm(form, variantAlert);
        variantForm.init();

        var attributeEditor = new AttributeEditor(form, variantForm);
        attributeEditor.init();
    });
});

var AttributeEditor = (function (form, formSetup) {
    /*********************************
     * Variables
     *********************************/

    form = $('form');

    var template = $('.variant_demo_row', form);
    var attributes = $('.variant_select', form).length;
    var modal = form.siblings('.newAttribute').appendTo('body');
    var manualHide = false;
    var triggerSelect = null;
    var oldOption = null;


    var init = function () {
        //setup the handlers
        //doing it this way allows us to overwrite the individual handlers with ease
        addNewAttributeHandler();
        removeAttributeHandler();
        selectFocusHandler();
        selectChangeHandler();
        attributeVisibilityHandler();
        modalFormSubmissionHandler();
        modalShowHandler();
        modalCancelClickHandler();
    };

    /*********************************
     * Add new attribute button handler
     *********************************/
    var addNewAttributeHandler = function () {

        $('.variant_attribute_add_new a', form).on('click keypress', function (e) {
            form.css('background-color', '#f00');
            //patched support for enter key
            if (e.type === 'keypress' && e.which != 13) {
                return true;
            }

            //clone the template row so we can edit it
            var newRow = template.clone().css('display', 'none').removeClass('hidden variant_demo_row').addClass('variant_row');

            //give each element in the clone it's unique name
            $('.variant_select', newRow).prop('name', 'attribute_key_' + attributes);
            $('.variant_input', newRow).prop('name', 'attribute_value_' + attributes);
            $('.variant_visible', newRow).prop('name', 'attribute_visible_' + attributes);

            //insert the new attribute row at the bottom of the attributes
            newRow.insertBefore($('.variant_attribute_add_new', form)).show('fast', function () {
                $('select', newRow).focus();
            });

            //we have added new nodes so we need to reset the validationEngine
            form.validationEngine('detach');
            formSetup.init();
            attributes++;
        });
    };

    /*********************************
     * Remove attribute button handler
     *********************************/
    var removeAttributeHandler = function () {

        form.on('click keypress', '.removeAttribute', {}, function (e) {

            //patched support for enter key
            if (e.type === 'keypress' && e.which != 13) {
                return true;
            }

            attributes--;

            var val = $(this).siblings('select').val();

            //re-enable whatever attribute key was in use
            if (val != "") {
                $('.variant_select option[value=' + val + ']', form).removeAttr('disabled');
            }

            //animate the removal of the attribute
            $(this).closest('.controls-row').hide('fast', function () {
                $(this).remove();
            });
        });
    };

    /*********************************
     * Attribute key select focus handler
     *********************************/
    var selectFocusHandler = function () {

        form.on('focus', '.variant_select', {}, function () {
            //store the old option so we know what option to
            //re-enable if a change is made
            oldOption = $('option:selected', this).val();
        });
    };

    /*********************************
     * Attribute key select change handler
     *********************************/
    var selectChangeHandler = function () {
        form.on('change', '.variant_select', {}, function () {
            var select = $(this);

            //empty class is used for "placeholder" simulation
            select.removeClass('empty');

            //re-enable whatever option was previously selected
            if (oldOption !== null) {
                $('.variant_select option[value=' + oldOption + ']', form).removeAttr('disabled');
            }

            if ($('option:selected', select).hasClass('newAttribute')) { //Add new attribute selected
                triggerSelect = select;
                modal.modal('show');
            } else if ($('option:selected', select).val() == "") { //Placeholder selected
                select.addClass('empty');
            } else { //Value selected
                //disable the selected value in other attribute key selects
                $('.variant_select', form).not(select).children('option[value=' + select.val() + ']').prop('disabled', 'disabled');
            }
            oldOption = select.val();
        });
    };

    /*********************************
     * Toggle visibility button handler
     *********************************/
    var attributeVisibilityHandler = function () {

        form.on('click', '.toggleVisibility', {}, function () {

            //the titles of the button
            var hidden = 'Hidden Attribute';
            var visible = 'Visible Attribute';

            var btn = $(this);
            var icon = btn.children('i');
            var box = btn.siblings('.variant_visible');

            //toggle the state between visible and hidden
            btn.toggleClass('btn-success btn-warning').attr('title', btn.attr('title') == hidden ? visible : hidden);
            icon.toggleClass('icon-eye-open icon-eye-close');
            box.prop("checked", !box.prop("checked"))
        });
    };

    /*********************************
     * New attribute submission handler
     *********************************/
    var modalFormSubmissionHandler = function () {

        $('.newAttributeForm', modal).validationEngine('attach', {
            onValidationComplete:function (form, status) {
                if (status) {
                    var text = $('.newAttributeName', modal).val();
                    $('.newAttributeName', modal).val('');
                    form.spin();

                    $.ajax({
                        type:'POST',
                        url:'/cfox/cart/variants/addattribute',
                        data:{name:text},
                        success:function (data) {
                            //add new attribute key to attribute key selects everywhere
                            $('.variant_select').append($('<option>', { value:data.id}).text(data.name));

                            //set the triggering selects value to the new key
                            triggerSelect.val(data.id);
                            triggerSelect.trigger('change');


                            manualHide = true;
                            modal.modal('hide');
                            triggerSelect.siblings('input').focus();
                            form.spin(false);
                        },
                        dataType:'JSON'
                    });

                }
            }});
    };

    var modalCancelClickHandler = function () {

        $('.btn-danger', modal).on('click', function () {
            if (!manualHide) {
                triggerSelect[0].selectedIndex = 1;
                triggerSelect.trigger('change');
            }
            manualHide = false;
        });
    };

    var modalShowHandler = function () {

        modal.on('show shown', function () {
            $('.newAttributeName', modal).focus();
        });
    }

    return AttributeEditor;


})();

var VariantForm = (function (form, variantAlert) {
    /*********************************
     * Variables
     *********************************/

    form = $('form');

    var init = function () {
        nameChangeHandler();
        submitHandler();
    };

    /*********************************
     * Variant name change handler
     * Changes the heading on the accordion if the
     * name form input changes
     *********************************/
    var nameChangeHandler = function () {
        var accordion_heading = form.closest('.accordion-body').siblings('.accordion-heading').find('.accordion-toggle');
        $('.name-input', form).on('change', function () {
            accordion_heading.text($(this).val());
        });
    };

    /*********************************
     * Form submit handler
     *********************************/
    var submitHandler = function () {
        form.validationEngine('attach', {
            onValidationComplete:function (form, status) {
                if (status == true) {
                    $.ajax({
                        type:'POST',
                        url:form.attr('action'),
                        data:form.serialize(),
                        dataType:'json',
                        beforeSend:function () {
                            cfox.disableForm(form);
                            form.spin();
                            form.children('.variant_status_message').hide('fast');
                        },
                        success:function (response) {
                            cfox.enableForm(form);//need to do this here so browser doesn't cache disabled fields
                            if (typeof response != "object" || response === null) {
                                variantAlert.message('failed');
                            } else {
                                switch (response.status) {
                                    case 0:
                                        variantAlert.message('errors', response.errors);
                                        break;
                                    case 1:
                                        variantAlert.message('success');
                                        break;
                                    default:
                                        variantAlert.message('failed');
                                        break;
                                }
                            }

                            form.spin(false);
                        },
                        error:function () {
                            variantAlert.message('failed');
                            form.spin(false);
                            cfox.enableForm(form);
                        }
                    });
                }
            }
        });
    }


})();

var VariantAlert = (function (form) {

    /*********************************
     * Variables
     *********************************/
    var timer;

    form = $('form');


    /*********************************
     * handles showing/hiding any messages
     * in the variant forms
     *********************************/
    var message = function (type, message) {
        var alert;
        clearTimeout(timer);
        $('.variant_status_message', form).hide('fast');
        if (type == 'success') {
            alert = $('.variant_status_message.success', form);
        } else if (type == 'errors') {
            alert = $('.variant_status_message.errors', form);
            $('.alert-message', alert).html(message);
        } else if (type == 'failed') {
            alert = $('.variant_status_message.failed', form);
        }

        alert.show('fast', function () {

            $('html, body').animate({
                scrollTop:alert.closest('.accordion-group').offset().top
            }, 150, 'linear');

            timer = setTimeout(function () {
                alert.hide('fast')
            }, 5000);
        });
    }


})();
Run Code Online (Sandbox Code Playgroud)

Dam*_*ask 1

你的variantAlert使用类似

 variantAlert.message('failed');
Run Code Online (Sandbox Code Playgroud)

这意味着构造函数必须返回包含消息函数的对象

var VariantAlert = function (form) {

var timer;

/*********************************
 * handles showing/hiding any messages
 * in the variant forms
 *********************************/
var message = function (type, message) {
    var alert;
    clearTimeout(timer);
    $('.variant_status_message', form).hide('fast');
    if (type == 'success') {
        alert = $('.variant_status_message.success', form);
    } else if (type == 'errors') {
        alert = $('.variant_status_message.errors', form);
        $('.alert-message', alert).html(message);
    } else if (type == 'failed') {
        alert = $('.variant_status_message.failed', form);
    }

    alert.show('fast', function () {

        $('html, body').animate({
            scrollTop:alert.closest('.accordion-group').offset().top
        }, 150, 'linear');

        timer = setTimeout(function () {
            alert.hide('fast')
        }, 5000);
    });        
}
return {
    message: message  
};
}
Run Code Online (Sandbox Code Playgroud)