Bygg en kontaktbehandler ved hjelp av Backbone.js Del 2

Velkommen tilbake til del to av denne opplæringen; i første del så vi på noen av modellene, samlingen og visningsgrunnlaget for når de jobbet med Backbone og så hvordan man gjengir individuelle kontaktvisninger ved hjelp av en hovedvisning bundet til en samling.

I denne delen av opplæringen skal vi se på hvordan vi kan filtrere vårt syn basert på brukerinngang, og hvordan vi kan legge til en ruter for å gi vår grunnleggende applikasjon noen nettadressefunksjonalitet.
Vi trenger kildefilene fra del ett da vi skal bygge på den eksisterende koden for denne delen. Jeg anbefaler på det sterkeste å lese del en hvis du ikke allerede har det.


Reagerer til brukerinngang

Du har kanskje lagt merke til i del ett at hver enkelt av våre individuelle modeller har en tilskrevet kalt type som kategoriserer hver modell basert på om det er knyttet til en venn, familiemedlem til kollega. La oss legge til et valgelement i vår hovedvisning som lar brukeren filtrere kontaktene basert på disse typene.

Nå kan vi hardkodes en valgmeny i vår underliggende HTML og manuelt legge til alternativer for hver av de forskjellige typene. Men dette ville ikke være veldig fremover å tenke; Hva om vi legger til en ny type senere, eller slett alle kontaktene til en bestemt type? Vår søknad har ennå ikke muligheten til å legge til eller fjerne kontakter (del tre spoilervarsel!), Men det er fortsatt best å ta hensyn til slike ting, selv i denne tidlige fasen av søknaden vår.

Som sådan kan vi enkelt bygge et utvalgselement dynamisk basert på eksisterende typer. Vi legger til en liten bit av HTML til den underliggende siden først; legg til følgende nye elementer i kontaktbeholderen:

 

Det er det, vi har en ytre element for å fungere som en generell beholder, innenfor hvilken er en annen beholder med en id attributt og a med noen forklarende tekst.

La oss nå bygge ", html:""); _.each (this.getTypes (), function (item) var option = $ ("

Den første av våre metoder, getTypes () Returnerer en matrise opprettet ved hjelp av Underscore uniq () metode. Denne metoden aksepterer en matrise som argument og returnerer en ny matrise som bare inneholder unike elementer. Matrisen vi passerer inn i uniq () Metoden genereres ved hjelp av Backbone plukke() metode, som er en enkel måte å trekke alle verdier av en enkelt attributt ut av en samling av modeller. Attributtet vi er interessert i her er type Egenskap.

For å forhindre tilfelleproblemer senere, bør vi også normalisere typene til små bokstaver. Vi kan bruke en iterator-funksjon, levert som det tredje argumentet til uniq (), å transformere hver verdi før den blir satt gjennom komparatoren. Funksjonen mottar gjeldende element som et argument, så vi returnerer bare elementet i små bokstaver. Det andre argumentet gikk til uniq (), som vi satt på falsk her er et flagg som brukes til å indikere om arrayet som sammenlignes, er sortert.

Den andre metoden, createSelect () er litt større, men ikke mye mer komplisert. Den eneste hensikten er å skape og returnere en ny .

Å faktisk gjengi element, med et alternativ for hver av de forskjellige typer kontakt:


Filtrerer visningen

Så nå har vi vår meny, kan vi legge til funksjonaliteten for å filtrere visningen når et alternativ er valgt. For å gjøre dette kan vi gjøre bruk av hovedvisningen arrangementer Tilordne å legge til en brukerhåndterer for brukergrensesnitt. Legg til følgende kode direkte etter vår renderSelect () metode:

hendelser: "endre #filter velg": "setFilter",

De arrangementer Attributt aksepterer et objekt av nøkkel: verdi par hvor hver nøkkel spesifiserer type arrangement og en velger for å binde hendelseshandleren til. I dette tilfellet er vi interessert i endring Event som vil bli sparket av element i #filter container. Hver verdi i objektet er hendelsesbehandleren som skal være bundet; i dette tilfellet spesifiserer vi setFilter som handler.

Deretter kan vi legge til den nye handleren:

setFilter: funksjon (e) this.filterType = e.currentTarget.value; this.trigger ( "change: filtertype"); ,

Alt vi trenger å gjøre i setFilter () funksjonen er satt en egenskap i hovedvisningen kalt filtertype, som vi satt til verdien av alternativet som ble valgt, som er tilgjengelig via currentTarget Egenskapen til hendelsesobjektet som automatisk overføres til vår handler.

Når eiendommen er lagt til eller oppdatert, kan vi også utløse en egendefinert endring hendelse for det å bruke eiendomsnavnet som navneområde. Vi ser på hvordan vi kan bruke denne tilpassede hendelsen i et øyeblikk, men før vi gjør det, kan vi legge til funksjonen som faktisk skal utføre filteret. etter setFilter () metode legg til følgende kode:

filterByType: funksjon () if (this.filterType === "all") this.collection.reset (kontakter);  annet this.collection.reset (kontakter, silent: true); var filterType = this.filterType, filtrert = _.filter (this.collection.models, funksjon (element) return item.get ("type"). toLowerCase () === filterType;); this.collection.reset (filtrert); 

Vi kontrollerer først om hovedvisningen er filtertype eiendommen er satt til alle; Hvis det er, gjenoppbygger vi bare samlingen med det komplette settet av modeller, hvor dataene lagres lokalt på vår kontakter matrise.

Hvis eiendommen ikke er lik alle, vi tilbakestiller fortsatt samlingen for å få alle kontaktene tilbake i samlingen, noe som kreves for å bytte mellom de forskjellige typer kontakt, men denne gangen setter vi inn stille alternativ til ekte (du vil se hvorfor dette er nødvendig på et øyeblikk) slik at tilbakestille hendelsen er ikke sparket.

Vi lagrer deretter en lokal versjon av visningen filtertype eiendom slik at vi kan referere det til en tilbakeringingsfunksjon. Vi bruker Underscore's filter() metode for å filtrere samlingen av modeller. De filter() Metoden aksepterer arrayet for å filtrere og en tilbakeringingsfunksjon for å utføre for hvert element i arrayet som blir filtrert. Tilbakeringingsfunksjonen passerer gjeldende element som et argument.

Tilbakeringingsfunksjonen kommer tilbake ekte for hvert element som har en type attributt tilsvarer verdien som vi nettopp lagret i variabelen. Typerne konverteres til små bokstaver på nytt, av samme grunn som tidligere. Eventuelle gjenstander som tilbakeringingsfunksjonen returnerer falsk for fjernes fra arrayet.

Når arrayet er filtrert, kaller vi tilbakestille() metode igjen, passerer i filtrert array. Nå er vi klare til å legge til koden som vil koble opp setType () metode, den filtertype eiendom og filterByType () metode.


Bindende hendelser til samlingen

I tillegg til bindende brukergrensesnitt hendelser til grensesnittet vårt ved hjelp av arrangementer Attributt, vi kan også binde hendelseshåndterere til samlinger. I vår setFilter () metode vi sparket en tilpasset hendelse, vi trenger nå å legge til koden som vil binde filterByType () metode til denne hendelsen; legg til følgende kode i initialize () Metoden til vår hovedvisning:

this.on ("change: filterType", this.filterByType, dette);

Vi bruker Backbone på() metode for å lytte etter vår tilpassede begivenhet. Vi spesifiserer filterByType () metode som håndteringsfunksjon for denne hendelsen ved hjelp av det andre argumentet til på(), og kan også angi konteksten for tilbakeringingsfunksjonen ved å sette inn dette som det tredje argumentet. De dette objekt her refererer til vår hovedvisning.

I vår filterByType funksjon, tilbakestiller vi samlingen for å repopulere den med enten alle modellene eller de filtrerte modellene. Vi kan også binde seg til tilbakestille arrangement for å gjenoppbygge samlingen med modellinstanser. Vi kan også spesifisere en håndteringsfunksjon for denne hendelsen, og det gode er at vi allerede har funksjonen. Legg til følgende linje av kode direkte etter endring hendelsesbinding:

this.collection.on ("reset", this.render, dette);

I dette tilfellet lytter vi etter tilbakestille Hendelsen og funksjonen vi ønsker å påberope er samlingen render () metode. Vi spesifiserer også at tilbakeringingen skal bruke dette (som i tilfelle av hovedvisningen) som sin sammenheng når den utføres. Hvis vi ikke leverer dette Som det tredje argumentet vil vi ikke kunne få tilgang til samlingen inne i render () metode når den håndterer tilbakestille begivenhet.

På dette tidspunktet bør vi nå finne at vi kan bruke markeringsboksen til å vise delsett av våre kontakter. Grunnen til at vi satte stille alternativ til sant i vår filterByType () Metoden er slik at visningen ikke gjenopprettes unødvendig når vi tilbakestiller samlingen ved starten av den andre grenen av det betingede. Vi må gjøre dette slik at vi kan filtrere etter en type, og deretter filtrere etter en annen type uten å miste noen modeller.


routing

Så det vi har så langt er greit, vi kan filtrere våre modeller ved hjelp av velg boksen. Men ville det ikke vært fantastisk hvis vi kunne filtrere samlingen ved hjelp av en nettadresse også? Ryggradens rutermodul gir oss denne muligheten, la oss se hvordan, og på grunn av den pent koblede måten vi har strukturert vår filtrering så langt, er det faktisk veldig enkelt å legge til denne funksjonaliteten. Først må vi utvide rutemodulen; Legg til følgende kode etter hovedvisningen:

var ContactsRouter = Ryggrad.Router.extend (ruter: "filter /: type": "urlFilter", urlFilter: funksjon (type) directory.filterType = type; directory.trigger ("change: filterType"); );

Den første egenskapen vi definerer i objektet som sendes til ruteren forlenge() metoden er ruter, som skal være et objekt bokstavelig hvor hver nøkkel er en URL for å matche og hver verdi er en tilbakeringingsfunksjon når nettadressen er matchet. I dette tilfellet søker vi etter nettadresser som starter med #filter og avslutt med noe annet. Del av URL-adressen etter filter/ En del er overført til funksjonen vi spesifiserer som tilbakekallingsfunksjonen.

Innenfor denne funksjonen setter vi opp eller oppdaterer filtertype Egenskapen til hovedvisningen og utløs vår tilpassede endring hendelsen igjen. Dette er alt vi trenger for å legge til filtreringsfunksjonalitet ved hjelp av nettadressen. Vi trenger likevel å lage en forekomst av ruteren vår, som vi kan gjøre ved å legge til følgende linje av kode direkte etter DirectoryView oppretting:

var contactsRouter = new ContactsRouter ();

Vi bør nå kunne skrive inn en nettadresse, for eksempel # Filter / familie og visningen vil gjengi seg selv for å vise bare kontaktene med typen familie:

Så det er ganske kult riktig? Men det er fortsatt en del mangler - hvordan vil brukerne vite å bruke våre fine nettadresser? Vi må oppdatere funksjonen som håndterer UI-hendelser på element slik at nettadressen oppdateres når velg boksen brukes.

For å gjøre dette krever to trinn; Først av alt bør vi aktivere Backbone's historisk støtte ved å starte historikk tjenesten etter at vår app er initialisert; legg til følgende linje med kode rett på slutten av skriptfilen vår (direkte etter at vi initialiserer ruteren):

Backbone.history.start ();

Fra dette punktet vil Backbone overvåke nettadressen for hashendringer. Nå, når vi vil oppdatere nettadressen etter at noe skjer, kaller vi bare navigere() metode for ruteren vår. Endre filterByType () metode slik at den ser slik ut:

filterByType: funksjon () if (this.filterType === "all") this.collection.reset (kontakter); contactsRouter.navigate ( "filter / all");  annet this.collection.reset (kontakter, silent: true); var filterType = this.filterType, filtrert = _.filter (this.collection.models, funksjon (element) return item.get ("type") === filterType;); this.collection.reset (filtrert); contactsRouter.navigate ("filter /" + filterType); 

Nå når velg boksen brukes til å filtrere samlingen, vil nettadressen bli oppdatert, og brukeren kan deretter bokmerke eller dele nettadressen, og de fremre og fremre knappene i nettleseren vil navigere mellom stater. Siden versjon 0.5 har Backbone også støttet pushState API, men for at dette skal fungere riktig må serveren gjøre gjeldende sider, som vi ikke har konfigurert for dette eksempelet, og bruker derfor standardhistorikkmodulen.


Sammendrag

I denne delen av opplæringen så vi på et par flere Backbone-moduler, spesielt rutene, History and Events-modulene. Vi har nå sett på alle de forskjellige modulene som følger med Backbone.

Vi så også på noen flere Underscore metoder, inkludert filter(), som vi brukte til å filtrere ned vår samling til bare de modellene som inneholder en bestemt type.

Til slutt så vi på Backbone's Router-modulen, som tillot oss å angi ruter som kan matches av applikasjonen vår for å utløse metoder og historikkmodulen som vi kan bruke til å huske tilstanden og holde nettadressen oppdatert med hashfragmenter.

Et poeng å ta bort er den løst koblede naturen til filtreringsfunksjonaliteten; da vi la til filtrering via valgmenyen, ble det gjort på en slik måte at det var veldig raskt og enkelt å komme sammen etterpå og legge til en helt ny metode for filtrering uten å måtte endre vår filter() metode. Dette er en av nøklene for å kunne bygge ikke-trivielle, vedlikeholdbare og skalerbare JavaScript-applikasjoner. Hvis vi ønsket det, ville det være veldig enkelt å legge til en helt ny filtreringsmetode, som måtte endre vår filtreringsmetode.

I neste del av denne serien går vi tilbake til å jobbe med modeller og se hvordan vi kan fjerne modeller fra, og legge til nye i samlingen.