javascript OOP 不工作 : Uncaught TypeError: object is not a function

标签 javascript jquery oop function

好的,背景故事是我们在页面上有一堆相同的(功能上的)表单来为产品添加变体, 该表格由三个主要部分组成。

属性编辑器

enter image description here
该组件允许用户向产品添加属性。 每个属性都有一个可见性状态、一个属性键、一个属性值和一个删除按钮,它们共同构成一个排。

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

每个 attribute key 选择列表都有一个 new attribute 选项,选择后会启动一个模式对话框,其中包含用于输入新属性名称的表单,然后该表单通过AJAX 并返回一个 ID,然后将新选项附加到页面上的每个 属性键 选择以允许选择它。

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

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


主窗体

enter image description here
该组件由变体的一般描述字段组成。 该表单通过 AJAX 提交并具有 jQuery Validation Engine附件用于表单验证。

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


警报系统

enter image description here
该组件处理逐个表单显示/隐藏错误/成功/状态消息。


问题

现在也有一些非常相似的形式,但在一些事件处理程序上略有不同,所以我想创建代码,这样我就可以随意替换其中的点点滴滴,而无需复制整个代码。

所以在遵循 this question 中的提示之后我最终得到了下面的代码,但我收到了错误: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);
    }


})();

完整版

$(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);
        });
    }


})();

最佳答案

你的 variantAlert 使用类似

 variantAlert.message('failed');

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

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

关于javascript OOP 不工作 : Uncaught TypeError: object is not a function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13225288/

相关文章:

javascript - React-Redux 类型错误 : dispatch is not a function

javascript - 验证后禁用/启用 onClick 事件?

javascript - 在 div 中使用箭头键

Javascript + 运算符

javascript - 如何创建隐藏菜单?

javascript - 是否可以为事件 : [] in FullCalendar? 中的每个事件设置颜色

c# - 如果我有冗长的数据类型会有问题吗?

java - 从文本文件中读取方法并在程序中执行它们

javascript - 使用 .attr() 后无法找到 .find() 标记

class - Kotlin 值与赋值中的引用