未捕获的类型错误:视图不是构造函数

时间:2017-03-18 22:18:27

标签: javascript jquery backbone.js

我有未捕获的类型错误:UserRegisterView不是构造函数。我不明白这个错误。我看了所有代码,但我没有找到它。 抱歉我的英语不好。请帮帮我

感谢您的回答

已更新

UserRegisterView就在这里

var UserRegisterView = Backbone.View.extend({

    model: User,
    el: '#form',
    events: {
        'click input[id="infoWeek"]': 'infoWeek',
        'click input[id="infoMonth"]': 'infoMonth'
    },

    infoWeek: function() {

        this.$el.find("#dayOfMonth").hide();
        this.render();
    },

    infoMonth: function() {

        this.$el.find("#dayOfWeek").hide();
        this.render();

    }
});

var AddUserView = Backbone.View.extend({
    el: $(".page"),
    events: {
        'click #saveUser': 'saveUser'
    },
    saveUser: function() {
        var user = new User();
        user.set({
            username: $("#username").val(),
            lastName: $("#lastName").val(),
            regNumber: $("#regNumber").val(),
            password: $("#password").val(),
            departmentName: $("#departmentName").val(),
            email: $("#email").val(),
            role: $("#role").val()
        });
        user.save();

        if (document.getElementById('isOpen').checked) {
            user.set("isOpen", $("#isOpen").val("1"));
            user.save();
        } else {
            user.set("isOpen", $("#isOpen").val("0"));
            user.save();
        }

        if (document.getElementById('dayOfWeek').checked) {
            user.set("dayOfWeek", $("#dayOfWeek").val());
            user.save();
        } else if (document.getElementById('dayOfMonth').checked) {
            user.set("dayOfMonth", $("#dayOfMonth").val());
            user.save();
        }


        $("#username").val("");
        $("#firstName").val("");
        $("#lastName").val("");
        $("#regNumber").val("");
        $("#password").val("");
        $("#deparmentName").val("");
        $("#email").val("");
        $("#isOpen").val("");
        $("#dayOfWeek").val("");
        $("#dayOfMonth").val("");
    },

    render: function() {
        var that = this;
        var template = Handlebars.compile(UserRegister);
        var myHtml = template(that.model.toJSON());
        that.$el.html(myHtml);
        return this;
    }
});

return {
    AddUserView: AddUserView,
    UserRegisterView: UserRegisterView
};

});

路由器用户功能。

define([
    'jquery',
    'underscore',
    'backbone',
    'handlebars',
    'spin',
    'app/models/LoginModel',
    'app/views/LoginView',
    'app/views/UserRegisterView'
], function($,
    _,
    Backbone,
    Handlebars,
    Spinner,
    Login,
    LoginView,
    UserRegisterView
) {

    var Router = Backbone.Router.extend({
        routes: {
            'search': 'search',
            'login': 'login',
            'travels': 'travels',
            'user': 'user',
            'menu': 'menu',
            '': 'home'

        },
        user: function() {

            disposeView(new UserRegisterView().render());

        }

在util.js上的dispose.view

function disposeView(view) {
    Backbone.View.prototype.close = function() {
        this.unbind();
        this.undelegateEvents();
    };

    /* Şu anki viewi yok et */
    if (this.currentView !== undefined) {
        this.currentView.close();
    }

    /* Yeni view oluştur. */
    this.currentView = view;
    this.currentView.delegateEvents();

    return this.currentView;
}

1 个答案:

答案 0 :(得分:1)

发生了什么

您的UserRegisterView模块返回一个包含两个构造函数的对象。

return {
    AddUserView: AddUserView,
    UserRegisterView: UserRegisterView
};

使用此模块时,您所获得的是上述对象。

define([
    // ...
    'app/views/UserRegisterView'
], function(
    // ...
    UserRegisterView // value of the return in the module
) {

因为它不是构造函数,而是包含构造函数的对象,所以你可以通过调用UserRegisterView 来误导自己。

要使用您的模块设置的当前方式获取新的UserRegisterView视图实例,您需要像这样调用它:

var userView = new UserRegisterView.UserRegisterView();

或者创建AddUserView实例:

var addView = new UserRegisterView.AddUserView();

解决方案

  • 拆分模块,每个视图构造函数一个。
  • 更改名称,至少它没有误导性(如UserViewsModule

其他改进

话虽如此,可以对您的Backbone代码进行其他改进。

var UserRegisterView = Backbone.View.extend({
    // that's useless (if not used) and not a view property.
    // model: User,

    // don't use `el` like that, especially when using the view as a shared Constructor
    el: '#form',
    events: {
        'click input[id="infoWeek"]': 'onInfoWeekClick',
        'click input[id="infoMonth"]': 'onInfoMonthClick'
    },

    initialize: function() {
        // Cache jQuery object of the view's element
        this.$dayOfMonth = this.$("#dayOfMonth");
        this.$dayOfMonth = this.$("#dayOfMonth");
        // also use the shortcut function instead of `this.$el.find()`
    }

    onInfoWeekClick: function(e) {
        this.$dayOfMonth.hide();
        // calling render here is useless unless your using it as a parent
        // view, where the child view overrides the render function.
    },

    onInfoMonthClick: function(e) {
        this.$dayOfMonth.hide();
    }
});

disposeView功能可以简化:

function disposeView(view) {
    var current = this.currentView;
    if (current) current.close();
    current = this.currentView = view;
    current.delegateEvents();
    return current;
}

每次调用函数时都不要更改默认的Backbone视图原型。相反,添加一次该功能。

_.extend(Backbone.View.prototype, {
    close: function() {
        this.unbind();
        this.undelegateEvents();
    },
    // any other function you want to add can go here.
});

在另一个答案中,我将详细介绍how to extend Backbone's core classes with requirejs transparently

您已经在使用jQuery,因此请不要使用JavaScript DOM API document.getElementById('isOpen')穿插jQuery选择器$('#isOpen')

我对以下视图做了一些改进。花点时间创建一些实用函数(如resetgetValues),以简化代码流并封装复杂性。

var AddUserView = Backbone.View.extend({
    el: $(".page"),
    events: {
        'click #saveUser': 'saveUser'
    },
    // compile the template once while creating the view class
    template: Handlebars.compile(UserRegister),

    // get the selector string out of the code and place them in one place
    // easy to change and maintain.
    fields: {
        username: "#username",
        firstName: "#firstName",
        lastName: "#lastName",
        regNumber: "#regNumber",
        password: "#password",
        deparmentName: "#deparmentName",
        email: "#email",
        isOpen: "#isOpen",
        dayOfWeek: "#dayOfWeek",
        dayOfMonth: "#dayOfMonth",
    },

    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        // cache jQuery object of every field once after a render
        this.field = _.reduce(this.fields, function(fields, selector, key) {
            fields['$' + key] = this.$(selector);
            return fields;
        }, {}, this);
        return this;
    },
    reset: function() {
        // reset all the fields once without repeating code.
        _.each(this.field, function($field) {
            $field.val("");
        });
        return this;
    },
    getValues: function(keys) {
        // get the value of multiple fields returned in a nice object
        // ready to be sent to a Backbone model.
        return _.reduce(keys, function(data, key) {
            data[key] = this.field[key].val();
            return data;
        }, {}, this);
    },

    saveUser: function() {
        var field = this.field,
            user = new User(this.getValues([
                'username',
                'lastName',
                'regNumber',
                'password',
                'departmentName',
                'email',
                'role',
            ]));

        user.set({ isOpen: field.$isOpen.is(':checked') });

        if (field.$dayOfWeek.is(':checked')) {
            user.set("dayOfWeek", field.$dayOfWeek.val());
        } else if (field.$dayOfMonth.is(':checked')) {
            user.set("dayOfMonth", field.$dayOfMonth.val());
        }

        user.save();
        this.reset();
    },
});

在以下代码段中,您将上下文(this)放入局部变量中。我看到了很多,我可以说在Stack Overflow问题上看到它的时间有90%,这没有任何意义。它显然是复制粘贴的尖叫声。

render: function() {
    var that = this;
    // ...
    that.$el.html(myHtml);
    return this;
}

请告诉我你看到你将this放入that,然后在整个功能中使用that,那么你仍然会返回this?!< / p>

在动态创建的回调中需要对象时,将上下文置于局部变量中非常有用。

render: function() {
    var that = this; // this is available here
    setTimeout(function() {
        // here this is not available.
        that.handleCallback();
    }, 10);
    // here we are in the same context as the first line.
    return this;
}