Entrare in Ember.js i prossimi passi

Nel mio articolo introduttivo ho esaminato le basi del framework Ember.js e i concetti fondamentali per la creazione di un'applicazione Ember. In questo articolo di approfondimento, ci addentreremo più in profondità in aree specifiche del framework per capire quante funzioni interagiscono per astrarre le complessità dello sviluppo di applicazioni a singola pagina.


Un'app di base

Ho notato in precedenza che il modo più semplice per ottenere i file necessari è andare al repository Github di Ember.js e tirare giù il kit di avvio, e questo è ancora valido. Questo kit include tutti i file necessari per avviare la tua esperienza Ember, quindi assicurati di scaricarlo da questo articolo.

La cosa interessante è che lo starter kit è anche un ottimo esempio di un'app Ember molto semplice. Passeggiamoci per capire cosa sta succedendo. Tieni presente che scaverò più in profondità in aree specifiche in seguito, quindi non preoccuparti se qualcosa non ha senso in questa sezione. È più per darti una comprensione di alto livello della funzionalità prima di immergerti nei dettagli.

Aperto index.html nel tuo browser, e vedrai quanto segue:

Benvenuto in Ember.js

  • rosso
  • giallo
  • blu

Questo non è molto eccitante, lo so, ma se guardi il codice che lo ha reso visibile, vedrai che è stato fatto con pochissimo sforzo. Se guardiamo "js / app.js", vediamo il seguente codice:

App = Ember.Application.create (); App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););

Al livello più elementare, un'app Ember ha bisogno solo di questa linea per essere considerata tecnicamente una "app":

App = Ember.Application.create ();

Questo codice imposta un'istanza dell'oggetto applicazione Ember, insieme a un modello di applicazione predefinito, listener di eventi e router applicativo. Prenditi un secondo e prova a pensare al codice che normalmente dovresti scrivere per creare uno spazio dei nomi globale, un modello sul lato client, associare i gestori di eventi all'interazione globale dell'utente e includere la cronologia e la gestione dello stato nel codice. Sì, quella riga fa tutto questo. Però sia chiaro, però: non sto dicendo che sta facendo tutto il lavoro per te, ma sta creando le basi su cui baserai, tramite una chiamata al metodo.

Il prossimo set di codice imposta il comportamento di un percorso, in questo caso, per il principale index.html pagina:

App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););

Ricordare che i percorsi vengono utilizzati per gestire le risorse associate a un URL specifico all'interno dell'applicazione e consentono a Ember di tenere traccia dei vari stati delle singole pagine. L'URL è l'identificatore chiave utilizzato da Ember per capire quale stato dell'applicazione deve essere presentato all'utente.

In questo caso, la rotta principale viene creata per impostazione predefinita in Ember. Potrei aver anche definito esplicitamente il percorso in questo modo:

App.Router.map (function () this.resource ('index', percorso: '/'); // Ci porta a "/");

Ma Ember si prende cura di questo per me per la "radice" della mia domanda. Tratteremo le rotte in modo più dettagliato in seguito.

Tornando al seguente codice:

App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););

In questo caso, quando un utente raggiunge la radice del sito, Ember imposterà un controller che caricherà un campione di dati con un nome semantico, chiamato soddisfare. Questi dati possono essere successivamente utilizzati nell'app, tramite questo controller che utilizza quel nome. E questo è specificamente ciò che accade in index.html. Apri il file e troverai quanto segue:

Questo è un modello sul lato client di Handlebars. Ricorda che Handlebars è la libreria di template per Ember ed è fondamentale per creare interfacce utente basate sui dati per la tua app. Ember utilizza gli attributi dei dati per collegare questi modelli ai controller che gestiscono i dati, indipendentemente dal fatto che siano specificati tramite un percorso o come controller autonomo.

Nel mio ultimo articolo ho menzionato che le convenzioni di denominazione sono importanti in Ember e che rendono semplici le funzionalità di connessione. Se osservi il codice del modello, vedrai che il nome del modello (specificato tramite -Template-name dati attributo) è "indice". Questo è utile e ha lo scopo di semplificare la connessione al controller specificato all'interno della rotta con lo stesso nome. Se guardiamo il codice di rotta ancora una volta, vedremo che si chiama "IndexRoute" e al suo interno c'è un controller con i dati impostati:

App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););

Il controller imposta un'origine dati denominata "contenuto" e la carica con una serie di stringhe per i colori. In sostanza, la matrice è il modello e il controller viene utilizzato per esporre gli attributi del modello.

Le convenzioni di denominazione consentono a Ember di collegare le risorse di questa rotta (ad es. Il controller con i dati) al modello specificato con lo stesso nome. Ciò fornisce al modello l'accesso ai dati esposti dal controller in modo che possa renderlo utilizzando le direttive di Handlebars. Da lì, gli elementi nell'array sono collegati tramite l'uso di Handlebars ' ogni direttiva e specificando l'alias modello che punta all'origine dati:

#each item in model 
  • articolo
  • /ogni

    Per essere più precisi, i dati vengono inseriti in voci di elenco create dinamicamente, generando così il markup per te al volo. Questa è la bellezza dei modelli lato client.

    Penso che questa app di base evidenzia come Ember astrae molte cose per te. Però è un po 'di magia nera e non è sempre facile capire come funzionano le cose. In realtà è successo a me e all'inizio le cose non sono andate bene. Quando inizi a capire le relazioni tra i vari componenti del framework, inizia a dare più senso. Iniziamo da zero per capire meglio questo.


    A partire da Ground Up

    Ho brevemente toccato l'oggetto dell'applicazione Ember e il fatto che costruisca le fondamenta per la tua applicazione. Le guide Ember svolgono un ottimo lavoro nel delineare in modo specifico l'istanziazione di un oggetto applicazione Ember:

    • Imposta lo spazio dei nomi dell'applicazione. Tutte le classi nella tua applicazione saranno definite come proprietà su questo oggetto (ad es. App.PostsView e App.PostsController). Questo aiuta a prevenire l'inquinamento dell'ambito globale.
    • Aggiunge i listener di eventi al documento ed è responsabile dell'invio di eventi alle proprie visualizzazioni.
    • Rappresenta automaticamente il modello dell'applicazione, il modello di root-in, in cui verranno renderizzati gli altri modelli.
    • Crea automaticamente un router e inizia il routing, basato sull'URL corrente.

    Quindi questa semplice affermazione:

    App = Ember.Application.create ();

    collega un sacco di pezzi fondamentali di cui dipenderà la tua applicazione. È importante notare questo App non è una parola chiave in Ember. È una normale variabile globale che stai usando per definire lo spazio dei nomi e potrebbe essere un nome di variabile valido. Da quello che ho visto, però, il nome della variabile, App, è una convenzione comunemente usata nella maggior parte delle app di Ember ed è in realtà raccomandata per rendere più facile copiare e incollare gran parte del codice di esempio creato nella comunità.

    Prendendo la lista sopra, ciò che Ember fa, attraverso quella linea, è essenzialmente creare questo codice automaticamente dietro le quinte:

    // Crea lo spazio dei nomi dell'applicazione App = Ember.Application.create (); // Crea il router globale per gestire lo stato della pagina tramite URL App.Router.map (function () ); // Crea il percorso dell'applicazione predefinito per impostare le proprietà dello stato a livello di applicazione App.ApplicationRoute = Ember.Route.extend (); // Crea il modello di applicazione predefinito 

    Pertanto, sebbene lo starter kit non definisse esplicitamente un router, una rotta o un modello con ambito applicativo, Ember si assicurava che fossero creati e disponibili in modo tale che la base della tua app fosse impostata e disponibile. È assolutamente ok creare esplicitamente il codice. In effetti, si consiglia di farlo se si intende passare dati o impostare attributi per l'istanza dell'oggetto applicazione.

    Ora ti starai chiedendo su questo "modello di applicazione" che viene visualizzato automaticamente e perché non lo vedi index.html. Questo perché è facoltativo creare esplicitamente il applicazione modello. Se è nel markup, Ember lo renderà immediatamente. Altrimenti, continua ad elaborare altre parti della tua applicazione normalmente. Il tipico caso d'uso per applicazione template sta definendo elementi dell'interfaccia utente globali, a livello di applicazione, come header e footer.

    Definire il applicazione template usa la stessa sintassi di stile di qualsiasi altro template tranne con una piccola differenza: il nome del template non ha bisogno di essere specificato. Quindi, definendo il tuo modello in questo modo:

     

    o questo:

     

    ti dà gli stessi risultati esatti. Ember interpreterà un modello con no -Template-name dati come modello dell'applicazione e lo renderà automaticamente all'avvio dell'applicazione.

    Se aggiorni index.html aggiungendo questo codice:

     

    Ora vedrai che il contenuto del tag di intestazione appare sopra il contenuto del modello di indice. Il manubrio presa direttiva funge da segnaposto nel applicazione modello, consentendo a Ember di iniettare altri modelli (che servono da wrapper di sorta) e di avere funzionalità di interfaccia utente globale come intestazioni e piè di pagina che circondano il contenuto e la funzionalità. Aggiungendo il applicazione modello a index.html, hai istruito Ember a:

    • Rendi automaticamente il applicazione modello
    • Inietti il ​​modello dell'indice nel applicazione modello tramite il manubrio presa direttiva
    • Elaborare e rendere immediatamente il file indice modello

    Un asporto importante è che tutto ciò che abbiamo fatto è stato aggiungere un modello (applicazione), e Ember si è occupata immediatamente del resto. Sono questi collegamenti alle funzionalità che rendono Ember.js un framework così potente con cui lavorare.


    Impostazione delle rotte

    Il routing è probabilmente il concetto più difficile da comprendere in Ember, quindi farò del mio meglio per suddividerlo in passaggi gestibili. Quando un utente naviga nella tua applicazione, deve esserci un metodo per gestire lo stato delle varie parti visitate dall'utente. È qui che arrivano il router dell'applicazione e i percorsi specifici per la posizione.

    L'oggetto router Ember è ciò che gestisce questo attraverso l'uso di percorsi che identificano le risorse necessarie per le posizioni delle specifiche. Mi piace pensare al router come a un vigile urbano che dirige le auto (utenti) verso strade diverse (URL e percorsi). I percorsi stessi sono legati a URL specifici e, quando si accede all'URL, le risorse dei percorsi sono rese disponibili.

    Guardando js / app.js di nuovo, noterai che è stata creata una rotta per la pagina principale (indice):

    App.IndexRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['red', 'yellow', 'blue']););

    Tuttavia, non esiste un'istanza del router. Ricorda che Ember creerà un router per impostazione predefinita se non ne specifichi uno. Creerà anche una voce di instradamento predefinita per la radice dell'applicazione simile a questa:

    App.Router.map (function () this.resource ('index', percorso: '/'););

    Questo indica a Ember che, quando viene colpita la radice dell'applicazione, deve caricare le risorse di un'istanza dell'oggetto di instradamento chiamata IndexRoute se è disponibile. Questo è il motivo per cui, nonostante non venga dichiarata alcuna istanza del router, l'applicazione continua a funzionare. Ember internamente sa che il percorso root dovrebbe essere nominato IndexRoute, lo cercheranno e caricheranno le sue risorse di conseguenza. In questo caso, sta creando un controller che conterrà i dati da utilizzare nel modello di indice.

    Poiché gli URL sono gli identificatori chiave utilizzati da Ember per gestire lo stato dell'applicazione, ognuno di essi avrà in genere un proprio gestore di route specificato se è necessario caricare risorse per quella sezione dell'app. Ecco cosa intendo; supponiamo di avere un'app con tre sezioni:

    • Account: (URL: / account)
    • Profilo (URL: / profilo)
    • Galleria (URL: / gallery)

    Nella maggior parte dei casi, ciascuna di queste sezioni avrà le proprie risorse uniche che devono essere caricate (ad es .: dati o immagini). Quindi dovresti creare gestori di percorsi usando il risorsa() metodo nell'istanza dell'oggetto router dell'applicazione di Ember come questo:

    App.Router.map (function () this.resource ('accounts'); this.resource ('profiles'); this.resource ('gallery'););

    Ciò consente a Ember di comprendere la struttura dell'applicazione e gestire le risorse, di conseguenza. Le definizioni di rotte saranno correlate alle singole istanze di oggetti di percorso che in realtà eseguono l'impostazione di sollevamento pesante o controllori di interfacciamento:

    App.GalleryRoute = Ember.Route.extend (setupController: function (controller) controller.set ('content', ['pic-1.png', 'pic-2.png', 'pic-3.png' ]););

    Quindi nell'esempio sopra, quando un utente visita "/ gallery", Ember.js crea un'istanza dell'oggetto Route di GalleryRoute, imposta un controller con i dati e visualizza il galleria modello. Ancora una volta, questo è il motivo per cui le convenzioni di denominazione sono così importanti in Ember.

    La tua applicazione potrebbe anche avere URL nidificati, come / Account / new

    Per queste istanze, è possibile definire le risorse Ember che consentono di raggruppare i percorsi insieme, in questo modo:

     App.Router.map (function () this.resource ('accounts', function () this.route ('new');););

    In questo esempio, abbiamo usato il risorsa() metodo per raggruppare i percorsi insieme e il itinerario() metodo per definire i percorsi all'interno del gruppo. La regola generale è da usare risorsa() per nomi (account e account sarebbero entrambi risorse anche se nidificati) e itinerario() per i modificatori: (verbi come nuovo e modificare o aggettivi come preferiti e ha recitato).

    Oltre a raggruppare i percorsi, Ember crea riferimenti interni a controller, rotte e modelli per ciascuna delle rotte di gruppo specificate. Questo è come sarebbe (e di nuovo tocca le convenzioni di denominazione di Ember):

    "/ conti":

    • Controller: AccountController
    • Percorso: AccountsRoute
    • Modello: account (sì è in minuscolo)

    "/ Account / new":

    • Controller: AccountNewController
    • Percorso: AccountsNewRoute
    • Modello: conti / nuovi

    Quando un utente visita "/ accounts / new" c'è un po 'di uno scenario genitore / figlio o master / dettaglio che si verifica. Ember prima assicurerà che le risorse per conti sono disponibili e rendono il conti modello (questa è la parte principale di esso). Quindi seguirà e farà lo stesso per "/ accounts / new", impostando le risorse e rendendo il accounts.new modello.

    Nota che le risorse possono anche essere annidate per strutture URL molto più profonde, come questa:

     App.Router.map (function () this.resource ('accounts', function () this.route ('new'); this.resource ('pictures', function () this.route ('aggiungi' ););););

    Prossimi passi

    Ho coperto molto materiale in questo post. Si spera che ciò abbia contribuito a semplificare alcuni aspetti di come funziona un'applicazione di Ember e come funzionano le rotte.

    Non abbiamo ancora finito, comunque. Nella prossima voce, mi tufferò nelle funzionalità di Ember per recuperare i dati e renderli disponibili con la tua app. È qui che entrano modelli e controllori, quindi ci concentreremo sulla comprensione di come i due lavorano insieme.