最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin0浏览0评论

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

<!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>
        pleted{
            text-decoration: line-through;
            color: #666;
        }
    </style>
    <script type="text/javascript" src=".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="<%= pleted ? 'pleted' : 'inplete' %>"><%= text %></span>
        <button class="plete"></button>
        <button class="delete"></button>
    </script>


    <script type="text/javascript">

        var Task = Backbone.Model.extend({
            defaults: {text: 'New task', pleted: 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);
            },

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

        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 plete': '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('pleted', !this.model.get('pleted'));
            },

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

            clearCompleted: function(){
                var pletedTasks = this.collectionpleted();
                this.collection.remove(pletedTasks);
            }

        });     

        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.

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

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 plaining
        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.

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...

Thanks.

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

<!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>
        .pleted{
            text-decoration: line-through;
            color: #666;
        }
    </style>
    <script type="text/javascript" src="http://code.jquery./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="<%= pleted ? 'pleted' : 'inplete' %>"><%= text %></span>
        <button class="plete"></button>
        <button class="delete"></button>
    </script>


    <script type="text/javascript">

        var Task = Backbone.Model.extend({
            defaults: {text: 'New task', pleted: 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);
            },

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

        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 .plete': '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('pleted', !this.model.get('pleted'));
            },

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

            clearCompleted: function(){
                var pletedTasks = this.collection.pleted();
                this.collection.remove(pletedTasks);
            }

        });     

        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.

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

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 plaining
        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.

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...

Thanks.

Share Improve this question asked May 23, 2014 at 7:42 awongCMawongCM 9275 gold badges22 silver badges47 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 0

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.collection of your view.

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

new TasksView({model: new Tasks()});
发布评论

评论列表(0)

  1. 暂无评论