Backbone.js的 - 用于实现与QUOT最佳实践;即时"搜索 [英] Backbone.js - Best Practice for Implementing "Instant" Search

查看:87
本文介绍了Backbone.js的 - 用于实现与QUOT最佳实践;即时"搜索的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的骨干应用的几个地方,我想有一个集合即时搜索,但我有一个很难拿出最好的方式来实现它。

Several places in my Backbone application I'd like to have an instant search over a collection, but I'm having a hard time coming up with the best way to implement it.

这里有一个快速的实现。 http://jsfiddle.net/7YgeE/ 请记住我的收藏品可能含有向上200款。

Here's a quick implementation. http://jsfiddle.net/7YgeE/ Keep in mind my collection could contain upwards of 200 models.

var CollectionView = Backbone.View.extend({

  template: $('#template').html(),

  initialize: function() {

    this.collection = new Backbone.Collection([
      { first: 'John', last: 'Doe' },
      { first: 'Mary', last: 'Jane' },
      { first: 'Billy', last: 'Bob' },
      { first: 'Dexter', last: 'Morgan' },
      { first: 'Walter', last: 'White' },
      { first: 'Billy', last: 'Bobby' }
    ]);
    this.collection.on('add', this.addOne, this);

    this.render();
  },

  events: {
    'keyup .search': 'search',
  },

  // Returns array subset of models that match search.
  search: function(e) {

    var search = this.$('.search').val().toLowerCase();

    this.$('tbody').empty(); // is this creating ghost views?

    _.each(this.collection.filter(function(model) {
      return _.some(
        model.values(), 
        function(value) {
          return ~value.toLowerCase().indexOf(search);
        });
    }), $.proxy(this.addOne, this));
  },

  addOne: function(model) {

    var view = new RowView({ model: model });
    this.$('tbody').append(view.render().el);
  },

  render: function() {

    $('#insert').replaceWith(this.$el.html(this.template));
      this.collection.each(this.addOne, this);
  }
});

和每个模型的一个微小的看法...

And a tiny view for each model...

var RowView = Backbone.View.extend({

  tagName: 'tr',

  events: {
    'click': 'click'
  },

  click: function () {
    // Set element to active 
    this.$el.addClass('selected').siblings().removeClass('selected');

    // Some detail view will listen for this.
    App.trigger('model:view', this.model);
  },

  render: function() {

    this.$el.html('<td>' + this.model.get('first') + '</td><td>' + this.model.get('last') + '</td>');
      return this;
  }
});

new CollectionView;

问题1

在每次的keydown,我过滤收集, TBODY ,然后呈现结果,从而为每个模型的新视图。我刚刚创建鬼的意见,是吗?会是最好妥善销毁每个视图?或者我应该尝试管理我的 RowView 取值...创建每个人只有一次,并通过他们向循环只呈现结果?在我的数组的CollectionView 也许?排空后, TBODY ,那份 RowViews 仍然有其或者是,现在空,需要重新呈现?

On every keydown, I filter the collection, empty the tbody, and render the results, thereby creating a new view for every model. I've just created ghost views, yes? Would it be best to properly destroy each view? Or should I attempt to manage my RowViews... creating each one only once, and looping through them to only render the results? An array in my CollectionView perhaps? After emptying the tbody, would the RowViews still have their el or is that now null and need to be re-rendered?

问题2,选型

您会注意到,我引发了​​我的 RowView 自定义事件。我想有一个详细视图某处处理该事件,并显示我的模型的全部。当我搜索我的列表中,如果我选择的模式仍然在搜索结果中,我想保持这种状态,让它留在我的详细信息视图。一旦它不再是我的结果,我会清空详细信息视图。所以,我一定会需要管理的意见数组,对不对?我认为是一个双向链表结构,其中每一个观点到它的模型,每个模型到它的看法......但如果​​我实现我在未来的车型单身的工厂,我不能强加在模型。 :/

You'll notice I'm triggering a custom event in my RowView. I'd like to have a detail view somewhere to handle that event and display the entirety of my model. When I search my list, if my selected model remains in the search results, I want to keep that state and let it remain in my detail view. Once it is no longer in my results, I'll empty the detail view. So I'll certainly need to manage an array of views, right? I've considered a doubly linked structure where each view points to it's model, and each model to it's view... but if I'm to implement a singleton factory on my models in the future, I can't impose that on the model. :/

那么,什么是管理这些意见的最佳方式?

So what's the best way to manage these views?

推荐答案

我忘乎所以,而你的问题玩一点点。

I got a little bit carried away while playing with your question.

首先,我将建立一个专门的回收举行过滤模型和一个状态模型来处理搜索。例如,

First, I would create a dedicated collection to hold the filtered models and a "state model" to handle the search. For example,

var Filter = Backbone.Model.extend({
    defaults: {
        what: '', // the textual search
        where: 'all' // I added a scope to the search
    },
    initialize: function(opts) {
        // the source collection
        this.collection = opts.collection; 
        // the filtered models
        this.filtered = new Backbone.Collection(opts.collection.models); 
        //listening to changes on the filter
        this.on('change:what change:where', this.filter); 
    },

    //recalculate the state of the filtered list
    filter: function() {
        var what = this.get('what').trim(),
            where = this.get('where'),
            lookin = (where==='all') ? ['first', 'last'] : where,
            models;

        if (what==='') {
            models = this.collection.models;            
        } else {
            models = this.collection.filter(function(model) {
                return _.some(_.values(model.pick(lookin)), function(value) {
                    return ~value.toLowerCase().indexOf(what);
                });
            });
        }

        // let's reset the filtered collection with the appropriate models
        this.filtered.reset(models); 
    }
});

这将被实例化

var people = new Backbone.Collection([
    {first: 'John', last: 'Doe'},
    {first: 'Mary', last: 'Jane'},
    {first: 'Billy', last: 'Bob'},
    {first: 'Dexter', last: 'Morgan'},
    {first: 'Walter', last: 'White'},
    {first: 'Billy', last: 'Bobby'}
]);
var flt = new Filter({collection: people});

然后我会创建列表和分离的观点输入字段:更容易维护,并左右移动

Then I would create separated views for the list and the input fields: easier to maintain and to move around

var BaseView = Backbone.View.extend({
    render:function() {
        var html, $oldel = this.$el, $newel;

        html = this.html();
        $newel=$(html);

        this.setElement($newel);
        $oldel.replaceWith($newel);

        return this;
    }
});
var CollectionView = BaseView.extend({
    initialize: function(opts) {
        // I like to pass the templates in the options
        this.template = opts.template;
        // listen to the filtered collection and rerender
        this.listenTo(this.collection, 'reset', this.render);
    },
    html: function() {
        return this.template({
            models: this.collection.toJSON()
        });
    }
});
var FormView = Backbone.View.extend({
    events: {
        // throttled to limit the updates
        'keyup input[name="what"]': _.throttle(function(e) {
             this.model.set('what', e.currentTarget.value);
        }, 200),

        'click input[name="where"]': function(e) {
            this.model.set('where', e.currentTarget.value);
        }
    }
});

基本视点允许改变到位DOM,请参阅Backbone,不与QUOT; this.el&QUOT;有关详细信息,包装

BaseView allows to change the DOM in place, see Backbone, not "this.el" wrapping for details

该实例看起来像

var inputView = new FormView({
    el: 'form',
    model: flt
});
var listView = new CollectionView({
    template: _.template($('#template-list').html()),
    collection: flt.filtered
});
$('#content').append(listView.render().el);

和在这个阶段 http://jsfiddle.net/XxRD7/2/

最后,我想修改的CollectionView 来嫁接在该行的观点我的渲染功能,像

Finally, I would modify CollectionView to graft the row views in my render function, something like

var ItemView = BaseView.extend({
    events: {
        'click': function() {
            console.log(this.model.get('first'));
        }
    }
});

var CollectionView = BaseView.extend({
    initialize: function(opts) {
        this.template = opts.template;
        this.listenTo(this.collection, 'reset', this.render);
    },
    html: function() {
        var models = this.collection.map(function (model) {
            return _.extend(model.toJSON(), {
                cid: model.cid
            });
        });
        return this.template({models: models});
    },
    render: function() {
        BaseView.prototype.render.call(this);

        var coll = this.collection;
        this.$('[data-cid]').each(function(ix, el) {
            new ItemView({
                el: el,
                model: coll.get($(el).data('cid'))
            });
        });

        return this;
    }
});

另一个小提琴 http://jsfiddle.net/XxRD7/3/

这篇关于Backbone.js的 - 用于实现与QUOT最佳实践;即时&QUOT;搜索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆