Bentornati alla seconda parte di questo tutorial; nella prima parte abbiamo esaminato alcune delle nozioni di base su modello, raccolta e visualizzazione per quando si lavorava con Backbone e ho visto come eseguire il rendering di singole viste di contatto utilizzando una vista principale associata a una raccolta.
In questa parte del tutorial, esamineremo come possiamo filtrare la nostra vista in base all'input dell'utente e come possiamo aggiungere un router per fornire alla nostra applicazione di base alcune funzionalità URL.
Avremo bisogno dei file di origine dalla prima parte mentre stiamo costruendo il codice esistente per questa parte. Consiglio vivamente di leggere la prima parte se non l'hai già fatto.
Potresti aver notato nella prima parte che ognuno dei nostri modelli ha un tipo chiamato attribuito che classifica ciascun modello in base al fatto che si riferisca ad un amico, un familiare di un collega. Aggiungiamo un elemento select alla nostra vista principale che consentirà all'utente di filtrare i contatti in base a questi tipi.
Ora, possiamo hardcode un menu di selezione nel nostro HTML sottostante e aggiungere manualmente le opzioni per ciascuno dei diversi tipi. Ma questo non sarebbe molto lungimirante; e se aggiungessimo un nuovo tipo più tardi o elimineremo tutti i contatti di un certo tipo? La nostra applicazione non ha ancora la capacità di aggiungere o rimuovere contatti (avviso di spoiler della terza parte!), Ma è ancora meglio prendere in considerazione questo tipo di cose, anche in questa fase iniziale della nostra applicazione.
Pertanto, possiamo facilmente creare un elemento di selezione in modo dinamico in base ai tipi esistenti. Prima aggiungeremo un minimo di HTML alla pagina sottostante; aggiungi i seguenti nuovi elementi al contenitore dei contatti:
Ecco, abbiamo un esterno elemento per agire come un contenitore generale, all'interno del quale è un altro contenitore con un
id
attributo e a con qualche testo esplicativo.
Ora costruiamo il elemento. Per prima cosa aggiungeremo due nuovi metodi al nostro
DirectoryView
vista mater; il primo estrarrà ogni tipo univoco e il secondo realizzerà effettivamente il menu a discesa. Entrambi i metodi dovrebbero essere aggiunti alla fine della vista:
getTypes: function () return _.uniq (this.collection.pluck ("type"), false, function (type) return type.toLowerCase ();); , createSelect: function () var filter = this.el.find ("filtro #"), select = $ ("", html:""); _.each (this.getTypes (), function (item) var option = $ ("", valore: item.toLowerCase (), text: item.toLowerCase ()). appendTo (select);); return select;
Il primo dei nostri metodi, GetTypes ()
restituisce una matrice creata usando Underscore uniq ()
metodo. Questo metodo accetta un array come argomento e restituisce un nuovo array contenente solo oggetti unici. La matrice che passiamo nel uniq ()
metodo viene generato utilizzando Backbone cogliere ()
metodo, che è un modo semplice per estrarre tutti i valori di un singolo attributo da una collezione di modelli. L'attributo a cui siamo interessati qui è il genere
attributo.
Al fine di prevenire problemi di casi in seguito, dovremmo anche normalizzare i tipi in lettere minuscole. Possiamo usare una funzione iteratrice, fornita come terzo argomento uniq ()
, per trasformare ogni valore prima che sia messo attraverso il comparatore. La funzione riceve l'argomento corrente come argomento, quindi restituiamo l'elemento in formato minuscolo. Il secondo argomento è passato a uniq ()
, che abbiamo impostato falso
qui, è un flag utilizzato per indicare se l'array confrontato è stato ordinato.
Il secondo metodo, createSelect ()
è leggermente più grande, ma non molto più complesso. Il suo unico scopo è creare e restituire un nuovo elemento, quindi possiamo chiamare questo metodo da qualche altra parte nel nostro codice e ricevere una nuova casella di riepilogo a discesa con un'opzione per ciascuno dei nostri tipi. Iniziamo dando il nuovo
Quindi usiamo Underscore's ogni()
metodo per iterare su ogni valore nella matrice restituita dal nostro GetTypes ()
metodo. Per ogni elemento nell'array creiamo un nuovo elemento, impostare il suo testo sul valore dell'elemento corrente (in lettere minuscole) e quindi aggiungerlo al
.
Per rendere effettivamente il elemento alla pagina, possiamo aggiungere del codice alla nostra vista principale
inizializzare()
metodo:
questo $ el.find ( "# filtro") aggiungere (this.createSelect ())..;
Il contenitore per la nostra vista principale è memorizzato nella cache in $ EL
proprietà che Backbone aggiunge automaticamente alla nostra classe di vista, quindi la usiamo per trovare il contenitore del filtro e aggiungere il
Se eseguiamo la pagina ora, dovremmo vedere il nostro nuovo elemento, con un'opzione per ciascuno dei diversi tipi di contatto:
Quindi ora abbiamo il nostro
eventi: "cambia # filtro seleziona": "setFilter",
Il eventi
l'attributo accetta un oggetto di Key: Value
accoppia in cui ogni chiave specifica il tipo di evento e un selettore a cui associare il gestore eventi. In questo caso siamo interessati a modificare
evento che verrà licenziato dal
Successivamente possiamo aggiungere il nuovo gestore:
setFilter: function (e) this.filterType = e.currentTarget.value; this.trigger ( "cambiamento: FilterType"); ,
Tutto ciò che dobbiamo fare nel setFilter ()
la funzione è impostata su una proprietà sulla vista principale chiamata Filtertype
, che impostiamo sul valore dell'opzione selezionata, che è disponibile tramite currentTarget
proprietà dell'oggetto evento che viene automaticamente passata al nostro gestore.
Una volta che la proprietà è stata aggiunta o aggiornata, possiamo anche attivare una custom modificare
evento per esso utilizzando il nome della proprietà come spazio dei nomi. Vedremo come possiamo utilizzare questo evento personalizzato in un attimo, ma prima di farlo, possiamo aggiungere la funzione che eseguirà effettivamente il filtro; dopo il setFilter ()
metodo aggiungi il seguente codice:
filterByType: function () if (this.filterType === "all") this.collection.reset (contacts); else this.collection.reset (contacts, silent: true); var filterType = this.filterType, filtered = _.filter (this.collection.models, function (item) return item.get ("type"). toLowerCase () === filterType;); this.collection.reset (filtrato);
Per prima cosa controlliamo se la vista principale è Filtertype
la proprietà è impostata su tutti
; se lo è, semplicemente ripopolare la raccolta con il set completo di modelli, i cui dati sono memorizzati localmente sul nostro contatti
schieramento.
Se la proprietà non è uguale tutti
, abbiamo comunque ripristinato la raccolta per recuperare tutti i contatti nella raccolta, necessaria per passare da un tipo di contatto all'altro, ma questa volta impostiamo silenzioso
opzione a vero
(vedrai perché questo è necessario in un momento) in modo che il reset
l'evento non è stato licenziato.
Quindi memorizziamo una versione locale delle viste Filtertype
proprietà in modo che possiamo fare riferimento a una funzione di callback. Usiamo Underscore's filtro()
metodo per filtrare la collezione di modelli. Il filtro()
metodo accetta l'array per filtrare e una funzione di callback da eseguire per ogni elemento dell'array che viene filtrato. La funzione di callback è passata alla voce corrente come argomento.
La funzione di callback tornerà vero
per ogni oggetto che ha un genere
attributo uguale al valore che abbiamo appena memorizzato nella variabile. I tipi vengono nuovamente convertiti in lettere minuscole, per lo stesso motivo di prima. Qualsiasi elemento restituito dalla funzione di callback falso
perché vengono rimossi dall'array.
Una volta che l'array è stato filtrato, chiamiamo il reset()
metodo ancora una volta, passando nell'array filtrato. Ora siamo pronti per aggiungere il codice che collegherà il setType ()
metodo, il Filtertype
proprietà e filterByType ()
metodo.
Oltre agli eventi UI vincolanti per la nostra interfaccia utilizzando il eventi
attributo, possiamo anche associare i gestori di eventi alle raccolte. Nel nostro setFilter ()
metodo abbiamo generato un evento personalizzato, ora abbiamo bisogno di aggiungere il codice che legherà il filterByType ()
metodo per questo evento; aggiungi il seguente codice al inizializzare()
metodo della nostra vista principale:
this.on ("change: filterType", this.filterByType, this);
Usiamo Backbone sopra()
metodo per ascoltare il nostro evento personalizzato. Specifichiamo il filterByType ()
metodo come funzione di gestore per questo evento utilizzando il secondo argomento di sopra()
, e può anche impostare il contesto per la funzione di callback impostando Questo
come il terzo argomento. Il Questo
l'oggetto qui si riferisce alla nostra vista principale.
Nel nostro filterByType
funzione, ripristiniamo la raccolta per ripopolarla con tutti i modelli o con i modelli filtrati. Possiamo anche legarci al reset
evento per ripopolare la raccolta con istanze di modello. Possiamo anche specificare una funzione di gestore per questo evento, e il bello è che abbiamo già ottenuto la funzione. Aggiungere la seguente riga di codice direttamente dopo modificare
associazione degli eventi:
this.collection.on ("reset", this.render, this);
In questo caso stiamo ascoltando il reset
evento e la funzione che vogliamo invocare è quella della collezione render ()
metodo. Specifichiamo anche che la callback dovrebbe usare Questo
(come nell'istanza della vista principale) come contesto in cui viene eseguita. Se non forniamo Questo
come terzo argomento, non saremo in grado di accedere alla raccolta all'interno di render ()
metodo quando gestisce il reset
evento.
A questo punto, dovremmo ora trovare che possiamo usare la casella di selezione per visualizzare i sottoinsiemi dei nostri contatti. Il motivo per cui abbiamo impostato il silenzioso
opzione per vero nel nostro filterByType ()
il metodo è tale che la vista non viene ridisegnata inutilmente quando reimposta la raccolta all'inizio del secondo ramo del condizionale. Dobbiamo fare in modo che possiamo filtrare in base a un tipo e quindi filtrare in base a un altro tipo senza perdere alcun modello.
Quindi, quello che abbiamo ottenuto finora va bene, possiamo filtrare i nostri modelli usando la casella di selezione. Ma non sarebbe fantastico se potessimo filtrare la collezione usando anche un URL? Il modulo router di Backbone ci offre questa capacità, vediamo come, e grazie al modo ben disaccoppiato con cui abbiamo strutturato il nostro filtro fino ad ora, è davvero facile aggiungere questa funzionalità. Per prima cosa dobbiamo estendere il modulo del router; aggiungi il seguente codice dopo la vista principale:
var ContactsRouter = Backbone.Router.extend (routes: "filter /: type": "urlFilter", urlFilter: function (type) directory.filterType = type; directory.trigger ("change: filterType"); );
La prima proprietà che definiamo nell'oggetto è passata al router estendere()
il metodo è itinerari
, che dovrebbe essere un oggetto letterale in cui ogni chiave è un URL da abbinare e ogni valore è una funzione di callback quando l'URL è abbinato. In questo caso stiamo cercando gli URL che iniziano con #filtro
e termina con qualsiasi altra cosa. La parte dell'URL dopo il filtro/
parte viene passata alla funzione che specifichiamo come funzione di callback.
All'interno di questa funzione impostiamo o aggiorniamo il Filtertype
proprietà della vista principale e quindi attivare la nostra abitudine modificare
evento ancora una volta. Questo è tutto ciò che dobbiamo fare per aggiungere funzionalità di filtro usando l'URL. Abbiamo comunque bisogno di creare un'istanza del nostro router, che possiamo fare aggiungendo la seguente riga di codice direttamente dopo DirectoryView
esemplificazione:
var contactsRouter = new ContactsRouter ();
Ora dovremmo essere in grado di inserire un URL come # Filtro / famiglia
e la vista verrà nuovamente visualizzata per mostrare solo i contatti con la famiglia di tipi:
Quindi è fantastico, vero? Ma manca ancora una parte: come faranno gli utenti a usare i nostri piacevoli URL? Abbiamo bisogno di aggiornare la funzione che gestisce gli eventi dell'interfaccia utente sul
Per fare questo richiede due passaggi; prima di tutto dovremmo abilitare il supporto della cronologia di Backbone avviando il servizio di cronologia dopo l'inizializzazione della nostra app; aggiungi la seguente riga di codice alla fine del nostro file di script (direttamente dopo aver inizializzato il nostro router):
Backbone.history.start ();
Da questo momento in poi, Backbone monitorerà l'URL per le modifiche hash. Ora, quando vogliamo aggiornare l'URL dopo che qualcosa accade, chiamiamo semplicemente il navigare()
metodo del nostro router. Cambiare il filterByType ()
metodo in modo che appaia così:
filterByType: function () if (this.filterType === "all") this.collection.reset (contacts); contactsRouter.navigate ( "filtro / all"); else this.collection.reset (contacts, silent: true); var filterType = this.filterType, filtered = _.filter (this.collection.models, function (item) return item.get ("type") === filterType;); this.collection.reset (filtrato); contactsRouter.navigate ("filter /" + filterType);
Ora, quando la casella di selezione viene utilizzata per filtrare la raccolta, l'URL verrà aggiornato e l'utente potrà quindi aggiungere un segnalibro o condividere l'URL, mentre i pulsanti Indietro e Avanti del browser navigeranno tra gli stati. Poiché la versione 0.5 Backbone ha anche supportato l'API pushState, tuttavia, affinché funzioni correttamente, il server deve essere in grado di eseguire il rendering delle pagine richieste, che non sono state configurate per questo esempio, quindi utilizzando il modulo di cronologia standard..
In questa parte del tutorial, abbiamo esaminato un paio di altri moduli Backbone, in particolare i moduli Router, History ed Events. Abbiamo esaminato tutti i diversi moduli forniti con Backbone.
Abbiamo anche esaminato alcuni altri metodi Underscore, tra cui filtro()
, che abbiamo usato per filtrare la nostra collezione solo per quei modelli contenenti un tipo specifico.
Infine, abbiamo esaminato il modulo Router di Backbone, che ci ha permesso di impostare percorsi che possono essere abbinati dalla nostra applicazione per attivare metodi e il modulo Cronologia che possiamo usare per ricordare lo stato e mantenere l'URL aggiornato con frammenti di hash.
Un punto da togliere è la natura liberamente accoppiata della nostra funzionalità di filtraggio; quando abbiamo aggiunto il filtro tramite il menu di selezione, è stato fatto in modo tale che fosse molto veloce e facile da seguire in seguito e aggiungere un metodo di filtraggio completamente nuovo senza dover cambiare il nostro filtro()
metodo. Questa è una delle chiavi per creare con successo applicazioni JavaScript non banali, gestibili e scalabili. Se lo volessimo, sarebbe molto facile aggiungere un altro metodo di filtro completamente nuovo, che deve cambiare il nostro metodo di filtraggio.
Nella parte successiva di questa serie, torneremo a lavorare con i modelli e vediamo come rimuovere i modelli e aggiungerne di nuovi alla raccolta.