javascript Backbone js - 未捕获的类型错误:无法读取未定义的属性“on”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23823652/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 01:37:54  来源:igfitidea点击:

Backbone js - Uncaught type error: Cannot read property 'on' of undefined

javascriptbackbone.jsunderscore.js

提问by awongCM

I have the following a very simple ToDo List app using Backbone framework.

我有以下使用 Backbone 框架的非常简单的待办事项列表应用程序。

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>To do List</title>
    <style>
        .completed{
            text-decoration: line-through;
            color: #666;
        }
    </style>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script type="text/javascript" src="js/underscore.js"></script>
    <script type="text/javascript" src="js/backbone.js"></script>
</head>
<body>

    <h1>My Todos</h1>
    <div id="tasks">

        <button class="add">Add Task</button>
        <button class="clear hide">Clear All</button>
        <ul></ul>           

    </div>

    <script id="taskTemplate" type="text/template">
        <span class="<%= completed ? 'completed' : 'incomplete' %>"><%= text %></span>
        <button class="complete"></button>
        <button class="delete"></button>
    </script>


    <script type="text/javascript">

        var Task = Backbone.Model.extend({
            defaults: {text: 'New task', completed: false}

        });

        var Tasks = Backbone.Collection.extend({
            model: Task,
            el: '#tasks',
            initialize: function(){
                this.collection = new Tasks;
                this.collection.on('add', this.appendNewTask, this);

                this.items = this.$el.children('ul');
            },

            add: function(){
                var text = prompt('What do you need to do?');
                var task = new Task({text: text});
                this.collection.add(task);
            },

            appendNewTask: function(task){
                var TasksView = new TasksView({model:task});
                this.items.append(TasksView.el);
            },

            completed: function(){
                return _.filter(this.models, function(model){
                    return model.get('completed');
                });
            }
        });

        var TasksView = Backbone.View.extend({
            tagName: 'li',
            el: '#tasks',
            template: _.template($('#taskTemplate').html()),

            initialize: function(){

                this.model.on('change', this.render, this);
                this.model.on('remove', this.unrender, this);
                this.render();
            },

            render: function(){
                var markup = this.template(this.model.toJSON());
                    this.$el.html(markup);
            },

            unrender: function(){
                this.$el.remove();
            },

            events: { 
                'click .add': 'add',
                'click .clear': 'clearCompleted',
                'click .delete': 'delete',
                'click .complete': 'updateStatus',
                'dblclick span': 'edit'
            },

            add: function(){
                    var text = prompt('What do you need to do?');
                    var task = new Task({text: text});
            },

            delete: function(){
                this.model.destroy();
                this.$el.remove();
            },

            updateStatus: function(){
                this.model.set('completed', !this.model.get('completed'));
            },

            edit: function(){
                var text = prompt('What should we change your task to?', this.model.get('text'))
                this.model.set('text',text);
            },

            clearCompleted: function(){
                var completedTasks = this.collection.completed();
                this.collection.remove(completedTasks);
            }

        });     

        new TasksView;

    </script>


    <!-- Template JS -->


</body>
</html>

When I visit and load the page, and I could see an uncaught javascript error in the console log.

当我访问并加载页面时,我可以在控制台日志中看到一个未捕获的 javascript 错误。

Uncaught TypeError: Cannot read property 'on' of undefinedon line 78.

未捕获的类型错误:无法读取第 78 行未定义的属性“on”

Looking through the code at the indictaed line number, it pointed to this

查看指示行号处的代码,它指向了这个

var TasksView = Backbone.View.extend({
    //.....
    initialize: function(){

        this.model.on('change', this.render, this); // this is the line the console is complaining
        this.model.on('remove', this.unrender, this);
        this.render();
    },
    //.....
});

After staring this for the next couple of hours and analysed the code, I couldn't figure out why this model needs to be instantiated when no tasks have been added to the TaskView Objects yet. It should be initialized as soon as I add or remove a new Task item into the model. I don't quite understand how this would throw an exception.

在接下来的几个小时内盯着它并分析了代码后,我无法弄清楚为什么在尚未将任务添加到 TaskView 对象时需要实例化此模型。一旦我在模型中添加或删除新的任务项,它就应该被初始化。我不太明白这将如何引发异常。

BTW, I'm a very new to Backbone.js and Underscore.js. I'm just following an online tutorial to figure out how these frameworks work...

顺便说一句,我是 Backbone.js 和 Underscore.js 的新手。我只是按照在线教程来弄清楚这些框架是如何工作的......

Thanks.

谢谢。

采纳答案by Anonymoose

You are not binding any model to your view. You can pass a model and/or collection when instantiating your new view. These properties will automatically be bound to this.model/ this.collectionof your view.

您没有将任何模型绑定到您的视图。您可以在实例化新视图时传递模型和/或集合。这些属性将自动绑定到您的视图的this.model/ this.collection

You are not passing a model so this.modelis undefined in your view. You should pass the empty taskslist so that when it's populated later, the onchangewill be triggered and your view will rerender.

您没有传递模型,因此this.model在您的视图中未定义。您应该传递空的任务列表,以便稍后填充它时,onchange将被触发并且您的视图将重新呈现。

new TasksView({model: new Tasks()});