2012-03-19 7 views
7

Sto usando un hub Signalr per iscriversi agli eventi sul server. Quale evento è stato inviato a un hub, è stato aggiunto correttamente a un Marionette CollectionView. Questo, a sua volta, viene reso a un tavolo.Can Backbone può eseguire il rendering di una raccolta in ordine inverso?

Poiché la tabella degli eventi è essenzialmente un blotter, mi piacerebbe gli eventi in ordine inverso e preferibilmente mantenere solo il n numero di eventi.

Can Backbone "automaticamente" esegue il rendering di una raccolta in ordine inverso?

risposta

1

Generalmente il rendering viene eseguito nella sottoclasse "Backbone.View". In modo da avere qualcosa di simile:

render: function() { 
    this.collection.each(function(model) { 
    // some rendering of each element 
    }, this); 
} 

this.collection è presumibilmente una sottoclasse Backbone.Collection, e così si può semplicemente utilizzare underscore.js methods su di esso per farlo in qualsiasi ordine che ti piace:

this.collection.reverse().each(...) 
this.collection.sort(function(m) { ... }).each(...) 

Ecc

Ovviamente, stai ricevendo un singolo elemento dal tuo back-end, e vuoi inserirlo nel posto giusto senza re-rendering dell'intera cosa! Quindi in questo caso basta andare a scuola e inserire la chiave di ordinamento come attributo rel o attributo data sugli elementi e utilizzarlo a insertAfter o simile con jQuery nel metodo renderNewItem (o simile).

+2

No reverse() - il metodo è disponibile nei metodi underscore.js purtroppo. – hbruce

+0

Haha buon punto! Non è davvero una pietra angolare della mia risposta, però. Puoi invertirlo usando un approccio diverso: '_.each (_.toArray (this.collection) .reverse(), function (m) {...});'. Oppure se stavi usando il coffeescript potresti semplicemente scrivere un ciclo for con un -1 step, ecc. – rfunduk

1

Backbone mantiene automaticamente le raccolte in ordine. Se si desidera utilizzare un ordinamento non predefinito, definire una funzione comparator() nella raccolta e verrà utilizzata al suo posto. Il comparatore può accettare uno o due argomenti, see the Backbone documentation per i dettagli.

È quindi possibile eseguire il rendering della raccolta in un ciclo .each() e verrà eseguita nell'ordine corretto. Tuttavia, l'aggiunta di nuovi elementi alla vista in ordine è a tua discrezione.

+0

Dira, buon punto, che rende più facile. Ma alla fine devi ancora inserirli nel DOM nel posto giusto. –

+1

Sì, quindi usi jnery's nth-child e after() o before() – dira

1

Da quanto descritto, non è necessario eseguire nuovamente il rendering della raccolta in ordine inverso. Basta aggiungere un evento per add alla raccolta in quella vista e chiamarlo una funzione che esegue il rendering dell'elemento appena aggiunto e lo antepone alla tabella.

this.collection.on('add', this.addItem); 
8

C'è un filo su questo argomento in https://github.com/marionettejs/backbone.marionette/issues/78

Anche se Backbone mantiene la raccolta differenziata, una volta si definisce un comparatore, come @breischl sottolineato, burattino non automaticamente ri-renderizzare il CollectionView in caso di modifiche di ordine . In effetti, Marionette ascolta l'evento add nella raccolta e aggiunge a un nuovo ItemView.

Se volete che il vostro CollectionView per visualizzare sempre gli elementi in ordine cronologico inverso, e si desidera che i nuovi elementi aggiunti per essere anteposto invece di allegata, quindi l'override del metodo appendHtml nel vostro CollectionView come segue:

var MyCollectionView = Backbone.Marionette.CollectionView.extend({ 
    appendHtml: function(collectionView, itemView){ 
    collectionView.$el.prepend(itemView.el); 
    } 
}); 

Se si desidera essere in grado di inserire in una posizione particolare come @dira menzionato nel commento, esiste una soluzione pubblicata nel link in alto su github di sberryman che riproduco qui per comodità (disclaimer: non ho testato il codice qui sotto personalmente):

Cambio appendHtml a:

appendHtml: function(collectionView, itemView) { 
    var itemIndex; 
    itemIndex = collectionView.collection.indexOf(itemView.model); 
    return collectionView.$el.insertAt(itemIndex, itemView.$el); 
} 

e aggiungere la seguente estendere jQuery per fornire insertAt funzione:

(function($) { 
    return jQuery.fn.insertAt = function(index, element) { 
    var lastIndex; 
    if (index <= 0) return this.prepend(element); 
    lastIndex = this.children().size(); 
    if (index >= lastIndex) return this.append(element); 
    return $(this.children()[index - 1]).after(element); 
    }; 
})(jQuery); 
+1

nota che in Marionette 2.x, appendHtml è stato cambiato in attachHtml. Spero che aiuti gli altri! Questo era esattamente ciò di cui avevo bisogno per visualizzare la collezione in ordine inverso, senza modificare l'ordine di altre logiche nella mia app web – mix3d

11

a passare attraverso la raccolta in ordine inverso io di solito uso una struttura come questa:

_.each(collection.last(collection.length).reverse(), function(model){ }); 
0

È possibile invertire i modelli in una raccolta come così ...

this.collection.models = this.collection.models.reverse() 
0

Se si utilizza lodash invece di sottolineatura si può anche fare questo:

_(view.collection.models).reverse(); 
0

come la spina dorsale non supporta l'iterazione inversa della collezione (ed è solo spreco di risorse per invertire o peggiorare la raccolta) l'approccio più semplice e veloce è quello di utilizzare il ciclo for con indice decrescente sui modelli nella raccolta.

for (var i = collection.length - 1; i >= 0; i--) { 
    var model = collection.models[i]; 

    // your logic 
} 

Non è che elegante come l'ordinamento o invertire la raccolta utilizzando Underscore ma la performace è molto meglio. Prova a confrontare diversi loop here solo per sapere quali costi ti costa foreach invece di classici per.

Problemi correlati