在 Backbonejs 中更新集合和视图

Updating collection and view in Backbonejs

我创建了一个搜索栏,但是当从用户那里收集数据时,它会再次显示默认数据,而不是用户新的搜索条件。

我正在重置集合并在用户搜索时给它一个新的 URL,但它似乎没有正确更新,我无法找出我的问题所在是。

(function(){
    'use strict';
    var red = red || {};

    //model////////////////////////////////////////////////

    red.RedditModel = Backbone.Model.extend({
        defaults: {
            urlTarget: $('#textBox').val(),
            urlStart: 'https://www.reddit.com/r/',
            urlEnd: '.json'
        },

        initialize: function() {

            this.on('change:urlTarget', function() {
                console.log('The Url Target has changed to ' + this.get("urlTarget"));
            });

            this.on('change:concatURL', function() {
                console.log('The model Url has changed to ' + this.get("concatURL"));
            });

            this.on('change:url', function() {
                console.log('The collection url has changed to: ' + this.get('url'));
            });

        }
    });
    var redditModel = new red.RedditModel();

    var fullURL = new red.RedditModel({

        concatURL: redditModel.attributes.urlStart + redditModel.attributes.urlTarget + redditModel.attributes.urlEnd
    });

    var listElmement,
        $list = $('.list');

    //collections//////////////////////////////////////////
    red.redditCollection = Backbone.Collection.extend({
        model: red.RedditModel,
        url: fullURL.attributes.concatURL,
        parse: function(response) {
            var redditData = response.data.children;
            return redditData;
        }
    });

    //view////////////////////////////////////

    red.RedditView = Backbone.View.extend({
        model: fullURL,
        collection: redditCollection,
        el: '.searchBar',
        events: {

            'click .searchButton': function(e) {
                this.updateModel(e);
                this.updateCollection(e);
            },
            'change #textBox': 'initialize'
        },

        updateModel: function() {
            this.$urlTarget = $('#textBox').val()
            this.model.set('urlTarget', this.$urlTarget);
            this.model.set('concatURL', redditModel.attributes.urlStart + this.$urlTarget + redditModel.attributes.urlEnd);
        },

        updateCollection: function() {
            this.collection.reset();
            this.$urlTarget = $('#textBox').val();
            var newUrl = redditModel.attributes.urlStart + this.$urlTarget + redditModel.attributes.urlEnd;
            this.collection.add({ urlTarget: this.$urlTarget });
            this.collection.add({ url: newUrl });
            console.log(newUrl);
        },

        tagName: 'li',
        className: 'listItems',

        initialize: function() {
            $list.html('');
            this.collection.fetch({
                success: function(redditData) {
                    redditData.each(function(redditData) {
                        redditData = redditData.attributes.data.title

                        listElmement = $('<li></li>').text(redditData);
                        $list.append(listElmement);

                    })
                }
            });
        },
        render: function() {

        }
    });

    var redditCollection = new red.redditCollection({
        redditModel,
        fullURL
    });

    var myRedditView = new red.RedditView({
        model: redditModel,
        collection: redditCollection
    });


    $('.page').html(myRedditView.render());;

})();

在模型中解析,并将其用于预期目的。无需在模型中存储 reddit url 和其他搜索相关信息。

red.RedditModel = Backbone.Model.extend({
    parse: function(data) {
        return data.data;
    },
})

因为你已经在这里处理了 reddit url。不要害怕在 Backbone 扩展对象(视图、模型、集合等)中创建一些实用函数和 getters/setters。

red.RedditCollection = Backbone.Collection.extend({
    url: function() {
        return 'https://www.reddit.com/r/' + this.target + this.extension;
    },

    initialize: function(models, options) {
        this.extension = '.json'; // default extension
    },

    setExtension: function(ext) {
        this.extension = ext;
    },
    setTarget: function(target) {
        this.target = target;
    },

    parse: function(response) {
        return response.data.children;
    }
});

不要害怕有很多视图,Backbone视图应该用来包装小组件逻辑。

所以这是项目:

red.RedditItem = Backbone.View.extend({
    tagName: 'li',
    className: 'listItems',
    render: function() {
        this.$el.text(this.model.get('title'));
        return this;
    }
});

列表使用的是:

red.RedditList = Backbone.View.extend({
    tagName: 'ul',
    initialize: function() {
        this.listenTo(this.collection, 'sync', this.render);
    },
    render: function() {
        this.$el.empty();
        this.collection.each(this.renderItem, this);
        return this;
    },
    renderItem: function(model) {
        var view = new red.RedditItem({ model: model });
        this.$el.append(view.render().el);
    }

});

而列表只是我们根视图的一个子组件(子视图)。

red.RedditView = Backbone.View.extend({
    el: '.searchBar',
    events: {
        'click .searchButton': 'onSearchClick',
    },

    initialize: function() {
        // cache the jQuery element for the textbox
        this.$target = $('#textBox');

        this.collection = new red.RedditCollection();

        this.list = new red.RedditList({
            collection: this.collection,
            // assuming '.list' is within '.searchBar', and it should
            el: this.$('.list'),
        });
    },
    render: function() {
        this.list.render();
        return this;
    },

    onSearchClick: function(e) {
        this.collection.setTarget(this.$target.val());
        console.log(this.collection.url());
        this.collection.fetch({ reset: true });
    },

});

那么,您只需具备以下条件即可使用:

var myRedditView = new red.RedditView();
myRedditView.render();

注意几乎不存在全局 jQuery 选择器的使用。如果您使用 Backbone 并且在任何地方都使用 $('#my-element'),那么您就违背了 Backbone 的目的,即在某种程度上将 MVC 概念应用于jQuery.

的顶部

发布的代码的一些注释

花点时间了解发生了什么。你的问题中有几行代码没有做任何事情,或者根本没有工作。


虽然它已在您的答案中删除,但以下内容没有意义,因为集合构造函数是 Backbone.Collection([models], [options]) 并且您在此处拥有的内容转换为传递 options 对象(使用 ES6 shorthand property names { a, b, c}) 到 models 参数。

var redditCollection = new red.redditCollection({
    redditModel,
    fullURL
});

这一行什么都不做,因为 .render() 什么都不做,return 什么也不做。

$('.page').html(myRedditView.render());

在这里,您正在使用 jQuery 手动创建一个新元素,而您有 Backbone 为您执行此操作。

$('<li></li>').text(redditData);

不要直接使用 attributes,除非有充分的理由,否则请始终使用 .get('attributeKey')

redditModel.attributes.urlStart

尽可能使用局部变量。这里的 listElement 变量是在 "app" 级别定义的,不需要它。

listElmement = $('<li></li>').text(redditData);
$list.append(listElmement);

Backbone 集合会在成功时自动填充模型的新实例。您不需要在成功回调中重新解析它(除了 redditData 的歧义)。

this.collection.fetch({
    success: function(redditData) {
        redditData.each(function(redditData) {
            redditData = redditData.attributes.data.title;

我不是有意无礼,我花时间写了这么长的答案,试图帮助你,以及任何未来的 reader。