1

Я относительно новичок в магистрали, и хотя я знаю общую идею о том, как ее использовать, мое обучение было быстрым, и, вероятно, я пропустил некоторые ключевые элементы.Как использовать оригинальную коллекцию мастей после фильтрации?

У меня есть коллекция, которая содержит атрибут под названием «тип», который может быть статьей, книгой, видео, классом. У меня есть представление рендеринга и все, но мне нужно иметь возможность фильтровать коллекцию при нажатии ссылок.

Мой вопрос: - как я могу его отфильтровать по коллекции и все еще иметь возможность обновлять исходную коллекцию, когда я нажимаю на другой тип?

Вот суть моего кода, я упростил для легкого чтения:

var TagsView = Backbone.View.extend({ 
    initialize: function(query) { 
     this.collection = new TagsCollection([], {query: self.apiQuery}); 
     this.collection.on('sync', function() { 
      self.render(); 
     }); 
     this.collection.on('reset', this.render, this); 
    }, 
    render: function() { 
     //renders the template just fine 
    }, 
    filter: function() { 
     //filtered does work correctly the first time I click on it but not the second. 
     var filtered = this.collection.where({'type':filter}); 
     this.collection.reset(filtered); 
    } 
}); 

обновление: мне удалось получить эту работу. Я закончил запуск события фильтра.

var TagsCollection = Backbone.Collection.extend({ 
    initialize: function(model, options) { 
     this.query = options.query; 
     this.fetch(); 
    }, 
    url: function() { 
     return '/api/assets?tag=' + this.query; 
    }, 
    filterBy: function(filter) { 
     filtered = this.filter(function(asset) { 
      return asset.get('type') == filter; 
     }); 
     this.trigger('filter'); 
     return new TagsCollection(filtered, {query: this.query}); 
    }, 
    model: AssetModel 
}); 

И затем, на мой взгляд, я добавил некоторые вещи для рендеринга моей новой коллекции.

var TagsView = Backbone.View.extend({ 
    initialize: function(query) { 
     this.collection = new TagsCollection([], {query: self.apiQuery}); 
     this.collection.on('sync', function() { 
      self.render(); 
     }); 
     this.collection.on('filter sync', this.filterTemplate, this); 
     this.collection.on('reset', this.render, this); 
    }, 
    render: function() { 
     //renders the template just fine 
    }, 
    filterCollection: function(target) { 
     var filter = $(target).text().toLowerCase().slice(0,-1); 
     if (filter != 'al') { 
      var filtered = this.collection.filterBy(filter); 
     } else { 
      this.render(); 
     } 

    }, 
    filterTemplate: function() { 
     filterResults = new TagsCollection(filtered, {query: self.apiQuery}); 
     console.log(filterResults); 
     $('.asset').remove(); 
     filterResults.each(function(asset,index) { 
      dust.render('dust/academy-card', asset.toJSON(),  function(error,output) { 
       self.$el.append(output); 
      }); 
     }); 
    }, 
}); 

ответ

1

Вот лучший ответ на этот вопрос. Вместо того, чтобы сделать это настолько сложным, вы можете просто использовать метод where. Вот мое решение для замены выше.

filterby: function(type) { 
     return type === 'all' ? this : new BaseCollection(this.where({type: type}); 
}); 
2

Причина, по которой она не работает во второй раз, заключается в том, что вы удаляете модели, которые не соответствуют вашему фильтру, когда вы вызываете reset. Это нормальное поведение для функции reset.

Вместо рендеринга с основной коллекцией вида попробуйте использовать вторую коллекцию только для рендеринга, которая представляет отфильтрованные данные исходной базовой коллекции. Таким образом, на ваш взгляд может выглядеть примерно так:

var TagsView = Backbone.View.extend({ 

    filter: null, 

    events: { 
     'click .filter-button': 'filter' 
    }, 

    initialize: function (query) { 
     this.baseCollection = new TagsCollection([], {query: self.apiQuery}); 
     this.baseCollection.on('reset sync', this.filterCollection, this); 
     this.collection = new Backbone.Collection; 
     this.collection.on('reset', this.render, this); 
    }, 

    render: function() { 
     var self = this, 
      data = this.collection.toJSON(); 

     // This renders all models in the one template 
     dust.render('some-template', data, function (error, output) { 
      self.$el.append(output); 
     }); 
    }, 

    filter: function (e) { 
     // Grab filter from data attribute or however else you prefer 
     this.filter = $(e.currentTarget).attr('data-filter'); 
     this.filterCollection(); 
    }, 

    filterCollection: function() { 
     var filtered; 

     if (this.filter) { 
      filtered = this.baseCollection.where({'type': this.filter}); 
     } else { 
      filtered = this.baseCollection.models; 
     } 

     this.collection.reset(filtered); 
    } 

}); 

Чтобы удалить все фильтры, установите кнопку с классом filter-button иметь пустой data-filter атрибут. collection будет сбрасываться со всех моделей baseCollection

+0

Благодарим за это. Хотя ваше решение не было тем, что я использовал, это побудило меня сделать что-то подобное. Я уточню свой ответ выше. –

+0

В чем смысл 'this.collection.on ('reset sync', this.render, this);'? Согласно вашему сообщению, исходная коллекция больше не будет сброшена, скорее будет отфильтрованная коллекция. Должна ли даже быть привязана к отфильтрованной коллекции? Кроме того, если исходная коллекция сбрасывается, делегированное событие в этой коллекции должно запускать «render», который был переопределен для рендеринга коллекции _filtered_? Я в замешательстве ... – seebiscuit

+0

@ Понятно, что вы правы в том, что вы стреляете в 'reset'. Причина в том, что он был в своем коде. Я просто держал его там для своей ясности. После повторного чтения это некоторые запутанные части. Я буду редактировать для ясности. – Simon

Смежные вопросы