2012-04-12 16 views
6

Konfiguruję aplikację opartą na sieci szkieletowej. Mam do czynienia z problemem "powinien być prosty", w którym mam model o nazwie "Message", kolekcję o nazwie "MessageList", a widok o nazwie "MessageView" i "MessageListView".Kolekcja kręgosłupa - filtrowanie i renderowanie kolekcji traci odwołanie do oryginalnej niefiltrowanej kolekcji

Kod MessageListView renderuje listę wiadomości. Mam 4 przyciski przełączania, które filtrują to, co pokazuje MessageListView. Przyciski filtra to "Wszystkie", "Aktywne", "Oznaczone" i "Zignorowane". "Wszystko" jest początkowym filtrem podczas ładowania strony. Gdy użytkownik naciśnie filtr "Flagged", powinny pojawić się tylko wiadomości z flagą == 1. Po ponownym naciśnięciu przycisku "Wszystkie" wszystkie komunikaty powinny pojawić się ponownie.

Problem, na który napotykam, a problem z moim projektem polega na tym, że po odfiltrowaniu kolekcji na podstawie metody filterString utracone zostanie odniesienie do oryginalnej całej kolekcji. Tak więc po ponownym naciśnięciu przycisku "Wszystkie" wiadomości zostały utracone.

Jestem ciekaw, najlepszy sposób to zrobić w Backbone ...

Oto kod instalacyjny ...

var messageListView = new MessageListView({collection: messageList}); 

Oto kod MessageListView ...

MessageListView = Backbone.View.extend({ 

    initialize : function() { 

     this.collection.on("add", function(model) { 
      var view = new MessageView({model: model}); 
      $("div.cameras").prepend(view.render().el); 
     }); 

     this.collection.on("remove", function(model) { 
      var ID = model.id; 
      $("#message-" + ID).parent("div.message").remove(); 
     }); 

     this.collection.on("reset", function(models) { 
      $("div.cameras").empty(); 
      models.each(function(message) { 
       var view = new MessageView({model: message}); 
       $("div.cameras").prepend(view.render().el); 
      }); 
     }); 

    }, 

    filterMessages : function(filterString) { 
     var filtered = this.collection.filter(function(model){ 

      if (filterString == "all") 
      { 
       return true; 
      } 
      else if (filterString == "active") 
      { 
       return model.get("ignore") == "0"; 
      } 
      else if (filterString == "ignore") 
      { 
       return model.get("ignore") == "1"; 
      } 
      else if (filterString == "flag") 
      { 
       return model.get("flag") == true; 
      } 

     }); 
     this.collection.reset(filtered); 
    }, 
+0

I upvoted zarówno pytanie i odpowiedź, dzięki chłopaki. Tylko wskazówka dla OP: wolałbym umieścić funkcje filtrowania w kolekcji itselft, a nie w widoku. Jest takie powiedzenie świata MVC, "Fat models, chudy kontrolerów". W Backbone View działa jako kontroler. A fakt, że kolekcje Backbone posiadają funkcje Underscore jest wskazówką w tym kierunku. – DjebbZ

Odpowiedz

10

Po wywołaniu

this.collection.reset(filtered) 

Odrzucasz stare dane i zastępujesz je nowymi danymi.

Zamiast tego chcemy mieć tymczasową "kolekcję" (tablica lub Backbone.Collection) do przechowywania wyników filtra i TO jest tym, co używasz jako "źródło danych" do renderowania Twoich Wiadomości do DOM.

Istnieje kilka sposobów na zrobienie tego.

  1. Po prostu wyrenderuj wyjście [array] funkcji filterMessages w każdym przypadku (łącznie z przypadkiem "all"), ale nie podawaj tego wyniku z powrotem do oryginalnej kolekcji.
  2. Utwórz drugą kolekcję, aby otrzymać wyniki funkcji filterMessages i zrenderować ją, pozostawiając nienaruszoną oryginalną kolekcję.
4

Można użyć Backbone.CollectionView, który pozwala określić, które modele w kolekcji są obecnie widoczne za pomocą opcji visibleModelsFilter.

kod instalacyjny ...

var messageListView = new MessageListView({ 
    collection: messageList, 
    modelView : MessageView 
}); 

kod MessageListView ...

MessageListView = Backbone.CollectionView.extend({ 

    filterMessages : function(filterString) { 
     if (filterString == "all") { 
      this.setOption("visibleModelsFilter", null); 
     } 
     else if (filterString == "active") { 
      this.setOption("visibleModelsFilter", function(thisModel) { 
       return model.get("ignore") == "0"; 
      }); 
     } 
     else if (filterString == "ignore") { 
      this.setOption("visibleModelsFilter", function(thisModel) { 
       return model.get("ignore") == "1"; 
      }); 
     } 
     else if (filterString == "flag") { 
      this.setOption("visibleModelsFilter", function(thisModel) { 
       return model.get("flag") == true; 
      }); 
     } 
    } 

}); 
Powiązane problemy