Creazione di una App Elenco Todo con Node.js e Geddy

In questo tutorial in tre parti, ci immergeremo profondamente nella creazione di un'app per la gestione delle liste in Node.js e Geddy. Questa è la seconda parte della serie, dove creeremo una semplice app per la gestione delle liste.


Ricapitolare

Come aggiornamento veloce, l'ultima volta che abbiamo installato Node e Geddy, abbiamo generato una nuova app e abbiamo imparato come avviare il server. In questo tutorial svilupperemo ciò che abbiamo fatto l'ultima volta, quindi assicurati di aver completato quello prima di continuare.


Generazione della risorsa Todo

Geddy ha un generatore di risorse integrato; questo ci consentirà di generare automaticamente un modello, un controller, viste e percorsi per una risorsa specifica. La nostra app per fare la lista avrà solo una risorsa: fare. Per generarlo, solo CD nella directory della tua app (cd percorso / a / tuo / todo_app) e corri:

geddy resource todo

Ora dovresti avere questi file aggiunti alla tua app:

  • app / models / todo.js
  • app / controller / todos.js
  • app / views / Todos /
    • index.html.ejs
    • show.html.ejs
    • edit.html.ejs
    • add.html.ejs

Il tuo config / router.js dovrebbe anche essere aggiunto a questo:

router.resource ( 'Todos');

Che cosa fa tutto

Se sei nuovo su MVC, tutto questo potrebbe sembrare un po 'scoraggiante per te. Non preoccuparti però, è davvero semplice una volta capito.

modelli / todo.js: Questo file è dove definiremo il nostro fare modello. Definiremo un numero di proprietà che tutto fare'farsi la barba. Scriveremo anche alcune convalide dei dati qui.

controllori / todos.js: Questo file è dove tutto il / Todos / i percorsi finiscono. Ogni azione in questo controller ha una rotta corrispondente:

GET / todos / => indice POST / todos / => crea GET / todos /: id => mostra PUT / todos /: id => Aggiorna DELETE / todos /: id => rimuovi GET / todos /: id / add = > aggiungi GET / todos /: id / edit => modifica

views / Todos /: Ogni file qui corrisponde a uno dei OTTENERE percorsi che ti abbiamo mostrato sopra. Questi sono i modelli che usiamo per generare il front-end dell'app. Geddy usa EJS (JavaScript incorporato) come linguaggio dei modelli. Dovrebbe sembrare familiare se tu abbia mai usato PHP o ERB. In pratica, puoi utilizzare qualsiasi JavaScript che desideri nei tuoi modelli.

Avere un'idea dei percorsi

Ora che abbiamo generato un sacco di codice, verifica che abbiamo tutti i percorsi di cui abbiamo bisogno. Avvia di nuovo l'app (Geddy) e indirizzare il browser a http: // localhost: 4000 / todos. Dovresti vedere qualcosa di simile

Vai avanti e prova quello per l'altro OTTENERE percorsi anche:

  • http: // localhost: 4000 / Todos / qualcosa
  • http: // localhost: 4000 / Todos / aggiungi
  • http: // localhost: 4000 / Todos / qualcosa / modificare

Tutto bene? Bene, continuiamo.


Creazione del modello da fare

In Geddy (e nella maggior parte degli altri framework MVC), utilizzi i modelli per definire il tipo di dati con cui la tua app funzionerà. Abbiamo appena generato un modello per il nostro fares, quindi vediamo cosa ci ha dato:

var Todo = function () // Qualche commento commentato; // Qualche altro codice commentato Todo = geddy.model.register ('Todo', Todo);

I modelli sono piuttosto semplici in Geddy. Stiamo solo creando una nuova funzione di costruzione per il nostro fares e registrandolo come modella in geddy. Definiamo alcune proprietà per il nostro fareS. Elimina tutto il codice commentato e aggiungilo alla funzione contructor:

var Todo = function () this.defineProperties (title: type: 'string', richiesto: true, id: tipo: 'stringa', richiesto: true, stato: tipo: 'stringa', obbligatorio : vero ); ;

Nostro fares avrà un titolo, un id e uno status, e tutti e tre saranno richiesti. Ora impostiamo alcune convalide per il nostro fareS.

var Todo = function () this.defineProperties (title: type: 'string', richiesto: true, id: tipo: 'stringa', richiesto: true, stato: tipo: 'stringa', obbligatorio : vero ); this.validatesPresent ( 'title'); this.validatesLength ('title', min: 5); this.validatesWithFunction ('status', function (status) return status == 'open' || status == 'done';); ;

Stiamo verificando che il titolo sia presente, che il titolo abbia una lunghezza minima di 5 caratteri e che stiamo utilizzando una funzione per verificare che lo stato sia Aperto o fatto. Ci sono alcune funzioni di valenza che sono integrate, vai avanti e controlla il progetto su http://github.com/mde/geddy per saperne di più su di loro.


Creazione dell'adattatore del modello Todo

Ora che abbiamo impostato il nostro modello, possiamo creare un punto in cui memorizzare i nostri modelli. Ai fini di questo tutorial, terremo i dati in memoria. Metteremo una serie di todos fuori dal nostro globale Geddy oggetto in cui inserire i dati. Nella parte successiva di questa serie, inizieremo a conservarli in un database.

Modifica del file init.js

Apri il tuo config / Init.js file. Tutto ciò che dovrebbe essere lì ora è un gestore globale di eccezioni non rilevate:

// Aggiungi il gestore di eccezioni non rilevate negli ambienti prod-if se (geddy.config.environment! = 'Sviluppo') process.addListener ('uncaughtException', function (err) geddy.log.error (JSON.stringify (err ));); 

Subito dopo quel blocco di codice, appendiamo il nostro array al Geddy globale:

geddy.todos = [];

Lì, ora abbiamo un posto dove riporre il nostro fareS. Ricorda, questo è nella memoria dell'applicazione, quindi scomparirà quando riavvierai il server.

Creazione dell'adattatore del modello

Un adattatore modello fornisce la base salvare, rimuovere, caricare, e tutti metodi di cui un modello ha bisogno. La nostra fonte di dati è piuttosto semplice (solo un array!), Quindi scrivere il nostro adattatore modello dovrebbe essere abbastanza semplice.

Crea una directory in lib chiamato model_adapters e creare un file in lib / model_adapters chiamato todo.js. Apriamo il file e aggiungiamo qualche codice di codice:

var Todo = new (function () ) (); exports.Todo = Todo;

Tutto quello che stiamo facendo qui è la creazione di un nuovo oggetto vuoto da esportare in qualunque cosa richieda questo file. Se desideri sapere qualcosa in più su come funziona il metodo Node, questo articolo ha una buona panoramica. In questo caso, il nostro Init.js il file farà il necessario.

Richiede l'adattatore del modello in init.js

Quindi abbiamo creato un nuovo oggetto adattatore Todo. Al momento è piuttosto sterile, ma ci arriveremo presto. Per ora, dovremo tornare a init.js e aggiungere del codice in modo che venga caricato nella nostra app all'avvio. Dopo il geddy.todos = []; nel config / Init.js aggiungi queste due linee:

geddy.model.adapter = ; geddy.model.adapter.Todo = require (process.cwd () + '/lib/model_adapters/todo').Todo;

Abbiamo creato un oggetto model-adapter vuoto e aggiunto l'adattatore del modello Todo su di esso.


Salvataggio di Todos

Ora che abbiamo installato il nostro modello e il nostro adattatore, possiamo iniziare con la logica dell'app. Iniziamo con l'aggiunta di elementi da fare nella nostra lista delle cose da fare.

Modifica il metodo di salvataggio sull'adattatore per salvare un'istanza di todo

Quando si lavora con i dati, il primo posto che si dovrebbe andare è l'adattatore del modello. Dobbiamo essere in grado di salvare un'istanza del nostro modello Todo nel nostro array geddy.todos. Quindi apriti lib / model_adapters / todo.js e aggiungi un metodo di salvataggio:

var Todo = new (function () this.save = function (todo, opts, callback) if (typeof callback! = 'function') callback = function () ; todo.saved = true; geddy. todos.push (todo); return callback (null, todo);) ();

Tutto ciò che dobbiamo fare è impostare la proprietà salvata dell'istanza su true e inserire l'elemento nell'array geddy.todos. In Node, è meglio fare tutto l'I / O in modo non bloccante, quindi è una buona idea prendere l'abitudine di usare i callback per passare i dati. Per questo tutorial non ha importanza, ma più avanti quando iniziamo a persistere, sarà utile. Noterai che ci siamo assicurati che il callback sia una funzione. Se non lo facciamo e usiamo save senza callback, avremo un errore. Ora passiamo al controller per creare un'azione.

Modifica l'azione create per salvare un'istanza di todo

Vai avanti e dai un'occhiata al creare azione in app / controller / todos.js:

this.create = function (req, resp, params) // Salva la risorsa, quindi visualizza la pagina index this.redirect (controller: this.name); ;

Abbastanza semplice, vero? Geddy l'ha soppressa per te. Quindi modifichiamolo un po ':

this.create = function (req, resp, params) var self = this, todo = geddy.model.Todo.create (title: params.title, id: geddy.string.uuid (10), stato: 'aperto '); todo.save (function (err, data) if (err) params.errors = err; self.transfer ('add'); else self.redirect (controller: self.name);) ; ;

Innanzitutto, creiamo una nuova istanza del modello Todo con geddy.model.Todo.create, passando il titolo che il nostro modulo ci invierà e impostando i valori predefiniti per l'ID e lo stato.

Quindi chiamiamo il metodo di salvataggio che abbiamo creato sull'adattatore del modello e reindirizziamo l'utente sulla rotta / todos. Se non ha superato la convalida, o riceviamo un errore, usiamo il controller trasferimento metodo per trasferire la richiesta nuovamente al Inserisci azione.

Modifica add.html.ejs

Ora è il momento per noi di impostare il modello di aggiunta. Dare un'occhiata al app / views / todos / add.html.ejs, Dovrebbe sembrare come questo:

Parametri

    <% for (var p in params) %>
  • <%= p + ': ' + params[p]; %>
  • <% %>

Non ne avremo bisogno

    per il nostro caso d'uso, quindi sbarazziamoci di esso per ora. Rendere il vostro add.html.ejs Assomiglia a questo:

    <%= partial('_form', params: params); %>

    Un'introduzione ai parziali

    Parziali ti offrono un modo semplice per condividere il codice tra i tuoi modelli.

    Noterai che stiamo usando un partial in questo template. Parziali ti offrono un modo semplice per condividere il codice tra i tuoi modelli. I nostri modelli di aggiunta e modifica useranno entrambi la stessa forma, quindi ora creiamo questo modulo in modo parziale. Crea un nuovo file nel views / Todos / directory chiamata _form.html.ejs. Usiamo un trattino basso per capire facilmente se questo modello è parziale. Aprilo e aggiungi questo codice:

    <% var isUpdate = params.action == 'edit' , formTitle = isUpdate ? 'Update this To Do Item' : 'Create a new To Do Item' , action = isUpdate ? '/todos/' + todo.id + '?_method=PUT' : '/todos' , deleteAction = isUpdate ? '/todos/' + todo.id + '?_method=DELETE' :", btnText = isUpdate ? 'Update' : 'Add' , doneStatus = isUpdate ? 'checked' :", titleValue = isUpdate ? todo.title :", errors = params.errors; %> 
    <%= formTitle %>
    <% if (errors) %>

    <% for (var p in errors) %>

    <%= errors[p]; %>
    <% %>

    <% %>
    <% if (isUpdate) %>
    <% %>
    <% if (isUpdate) %> <% %>

    Whoa, questo è un sacco di codice lì! Vediamo se possiamo attraversarlo. Dal momento che due template differenti useranno questo partial, dobbiamo assicurarci che il form abbia un aspetto giusto in entrambi. La maggior parte di questo codice è in realtà un file standard da Bootstrap di Twitter. È ciò che permette a questa app di apparire così buona da subito (e anche sui dispositivi mobili!).

    Per rendere questa app ancora più bella, puoi utilizzare il file CSS fornito nel download dell'app demo.

    La prima cosa che abbiamo fatto è stata impostare alcune variabili da utilizzare. Nel Inserisci azione che stiamo passando a params oggetto fino al modello nel rispondere chiamata al metodo. Questo ci dà alcune cose - ci dice quale controller e azione è stata indirizzata a questa richiesta, e ci fornisce tutti i parametri di query che sono stati passati nella url. Abbiamo istituito il isUpdate variabile per vedere se siamo attualmente sull'azione di aggiornamento, e quindi impostiamo alcune altre variabili per aiutare a ripulire il nostro codice di visualizzazione.

    Da lì, tutto ciò che abbiamo fatto è stato creare un modulo. Se siamo sull'azione di aggiunta, eseguiamo semplicemente il rendering del modulo così com'è. Se siamo nell'azione di modifica, compiliamo il modulo per consentire all'utente di aggiornare i campi.

    Si noti che il modulo invierà a INVIARE richiesta al / Todos / con un _method = PUT parametro. Geddy usa il metodo standard per sostituire i parametri per consentire l'invio METTERE e ELIMINA richiede dal browser senza dover utilizzare JavaScript. (almeno nella parte frontale!)

    L'ultimo piccolo dettaglio che dobbiamo dare un'occhiata è il pulsante "Rimuovi". Stiamo usando html5 FormAction attributo per cambiare l'azione per questo modulo. Noterai che questo pulsante FormAction manda un INVIARE richiesta fino al / Todos /: id percorso con a _method = CANCELLA parametro. Questo colpirà il rimuovere azione sul controller, che otterremo in seguito.

    Riavvia il tuo server (Geddy) e visita http: // localhost: 4000 / todos / add per vedere il tuo modello in azione. Crea un oggetto To Do mentre ci sei.


    Elenco di tutti i Todos

    Ora che abbiamo inserito gli elementi di input da fare dell'utente nel nostro array geddy.todos, dovremmo probabilmente elencarli da qualche parte. Iniziamo dal tutti metodo nell'adattatore del modello.

    Modifica il metodo all sull'adattatore per elencare tutti i modelli

    Apriamo lib / model_adapters / todo.js ancora e aggiungi un tutto il metodo giusto sopra ilsalva 'metodo:

    this.all = function (callback) callback (null, geddy.todos); 

    Questo è probabilmente il più semplice metodo di adattamento del modello che creeremo oggi, tutto ciò che fa è accettare un callback e chiamarlo con un errore (che è sempre nullo per ora, aggiorneremo questo metodo nel prossimo tutorial), e geddy.todos.

    Modifica l'azione dell'indice per mostrare tutti gli altri

    Aprire /app/controllers/todos.js di nuovo e dare un'occhiata al indice azione. Dovrebbe assomigliare a qualcosa di simile a questo:

    this.index = function (req, resp, params) this.respond (params: params); ;

    Questa parte è molto semplice, usiamo solo il tutti metodo che abbiamo appena definito sul modello-adattatore per ottenere tutto il fares e renderli:

    this.index = function (req, resp, params) var self = this; geddy.model.adapter.Todo.all (function (err, todos) self.respond (params: params, todos: todos);); ;

    Questo è tutto per il controller, ora sulla vista.

    Modifica index.html.ejs

    Dai uno sguardo a /app/views/todos/index.html.ejs, dovrebbe assomigliare a questo:

    Parametri

      <% for (var p in params) %>
    • <%= p + ': ' + params[p]; %>
    • <% %>

    Sembra molto simile al modello add.html.ejs, non è così. Ancora una volta, non avremo bisogno del parametro paramplan qui, quindi prendilo e rendi il tuo modello index.html.ejs simile a questo:

    Lista di cose da fare

    Crea una nuova attività

    <% if (todos && todos.length) %> <% for (var i in todos) %>

    / Modifica "><%= todos[i].title; %>

    <%= todos[i].status; %>

    <% %> <% %>

    Anche questo è piuttosto semplice, ma questa volta abbiamo un ciclo nel nostro modello. Nell'intestazione abbiamo aggiunto un pulsante per aggiungere nuovi dettagli. All'interno del ciclo stiamo generando una riga per ciascuno fare, mostrandone il titolo (come link ad esso modificare pagina), ed è lo stato.

    Per verificarlo, vai su http: // localhost: 4000 / todos.


    Modifica di un Todo

    Ora che abbiamo un link al modificare pagina, dovremmo probabilmente farlo funzionare!

    Creare un metodo di caricamento nell'adattatore del modello

    Apri di nuovo l'adattatore del modello (/lib/model_adapters/todo.js). Aggiungeremo a caricare metodo in modo che possiamo caricare uno specifico fare e usarlo nella nostra pagina di modifica. Non importa dove lo aggiungi, ma per ora mettiamolo tra il tutti metodo e il salvare metodo:

    this.load = function (id, callback) for (var i in geddy.todos) if (geddy.todos [i] .id == id) return callback (null, geddy.todos [i]);  callback (message: "To Do not found", null); ;

    Questo metodo di caricamento richiede un ID e un callback. Passa attraverso gli elementi in geddy.todos e controlla se l'elemento corrente è id corrisponde al passato id. Se lo fa, chiama il callback, passando il fare oggetto indietro. Se non trova una corrispondenza, chiama la richiamata con un errore. Ora dobbiamo usare questo metodo nell'azione show del controller di todos.

    Modifica l'azione di modifica per trovare un punto

    Apri il tuo Todos controller di nuovo e dare un'occhiata è modificare azione. Dovrebbe assomigliare a qualcosa di simile a questo:

    this.edit = function (req, resp, params) this.respond (params: params); ;

    Usiamo il metodo di caricamento che abbiamo appena creato:

    this.edit = function (req, resp, params) var self = this; geddy.model.Todo.load (params.id, function (err, todo) self.respond (params: params, todo: todo);); ;

    Tutto quello che stiamo facendo qui è caricare il todo e inviarlo al modello da renderizzare. Quindi diamo un'occhiata al modello.

    Modifica edit.html.ejs

    Aprire /app/views/todos/edit.html.ejs. Ancora una volta non avremo bisogno del parametro paramsplan, quindi rimuoviamolo. Rendere il vostro edit.html.ejs Assomiglia a questo:

    <%= partial('_form', params: params, todo: todo); %>

    Questo dovrebbe sembrare molto simile al add.html.ejs file che abbiamo appena modificato. Noterai che stiamo inviando un fare oggetto fino al parziale così come i parametri questa volta. La cosa interessante è che, poiché abbiamo già scritto il partial, questo è tutto ciò che dovremo fare per far sì che la pagina di edit venga visualizzata correttamente.

    Riavvia il server, creane uno nuovo fare e fai clic sul link per vedere come funziona. Ora facciamo funzionare il pulsante di aggiornamento!

    Modificare il metodo di salvataggio nell'adattatore del modello

    Aprire nuovamente l'adattatore del modello e trovare il salvare metodo. aggiungeremo un po 'in modo che possiamo salvare su esistenti fareS. Assomigli a questo:

    this.save = function (todo, opts, callback) if (typeof callback! = 'function') callback = function () ;  var todoErrors = null; per (var i in geddy.todos) // se è già lì, salvalo se (geddy.todos [i] .id == todo.id) geddy.todos [i] = todo; todoErrors = geddy.model.Todo.create (todo) .errors; return callback (todoErrors, todo);  todo.saved = true; geddy.todos.push (todo); return callback (null, todo); 

    Questo loop su tutto il todo è dentro geddy.todos e se il id è già lì, lo sostituisce fare con il nuovo fare esempio. Stiamo facendo alcune cose qui per assicurarci che le nostre convalide funzionino su aggiornamenti e creazioni - per fare questo dobbiamo tirare errori proprietà fuori da una nuova istanza del modello e passarla nuovamente nella richiamata. Se ha superato le convalide, sarà solo indefinito e il nostro codice lo ignorerà. Se non è passato, todoErrors sarà una matrice di errori di convalida.

    Ora che abbiamo questo, lavoriamo sul nostro controller aggiornare azione.


    Modifica l'azione di aggiornamento per trovare un punto, cambiare lo stato e salvarlo

    Vai avanti e riapri il controller e trova l'azione "aggiorna", dovrebbe assomigliare a questo:

    this.update = function (req, resp, params) // Salva la risorsa, quindi visualizza la pagina item this.redirect (controller: this.name, id: params.id); ;

    Dovrai modificarlo per farlo apparire come questo:

    this.update = function (req, resp, params) var self = this; geddy.model.adapter.Todo.load (params.id, function (err, todo) todo.status = params.status; todo.title = params.title; todo.save (function (err, data) if ( err) params.errors = err; self.transfer ('edit'); else self.redirect (controller: self.name););); ;

    Quello che stiamo facendo qui sta caricando il richiesto fare, modificarne alcune proprietà e salvarle fare ancora. Il codice che abbiamo appena scritto nel model-adapter dovrebbe gestire il resto. Se otteniamo un errore, significa che le nuove proprietà non hanno superato la convalida, quindi trasferiremo la richiesta al modificare azione. Se non avessimo ricevuto un errore, reindirizzeremo la richiesta nuovamente al indice azione.

    Vai avanti e provalo. Riavvia il server, creane uno nuovo fare, clicca sul suo link di modifica, cambia lo stato in fatto, e vedere che viene aggiornato nel indice. Se si desidera verificare il funzionamento delle convalide, provare a modificare il file titolo a qualcosa di più breve di 5 caratteri.

    Ora otteniamo che il pulsante "Rimuovi" funzioni.


    Rimozione di un Todo

    Ormai abbiamo un programma di lavoro da fare, ma se inizi a utilizzarlo per un po ', sarà difficile trovare il fare oggetto che stai cercando su quella pagina indice. Facciamo in modo che il pulsante "Rimuovi" funzioni così che possiamo mantenere la nostra lista piacevole e breve.

    Creare un metodo di rimozione nell'adattatore del modello

    Apriamo nuovamente il nostro adattatore per modello, questa volta vorremmo aggiungere un rimuovere metodo in là. Aggiungilo subito dopo salvare metodo:

    this.remove = function (id, callback) if (typeof callback! = 'function') callback = function () ;  for (var i in geddy.todos) if (geddy.todos [i] .id == id) geddy.todos.splice (i, 1); return callback (null);  return callback (message: "To Do not found"); 

    Questo è piuttosto semplice, dovrebbe somigliare molto al metodo di caricamento. Attraversa tutto il fares in geddy.todos trovare il id che stiamo cercando. Quindi giunge a quel punto dall'array e chiama il callback. Se non lo trova nella matrice, chiama la richiamata con un errore.

    Usiamo questo nel nostro controller ora.

    Modifica l'azione di rimozione

    Apri di nuovo il controller e tocca il rimuovere azione. Dovrebbe assomigliare a qualcosa di simile a questo:

    this.remove = function (req, resp, params) this.respond (params: params); ;

    Modificalo per farlo apparire come questo:

    this.remove = function (req, resp, params) var self = this; geddy.model.adapter.Todo.remove (params.id, function (err) if (err) params.errors = err; self.transfer ('edit'); else self.redirect (controller: self .nome);  ); 

    Noi passiamo il id che abbiamo ottenuto dai params nel modulo post in rimuovere metodo che abbiamo appena creato. Se riceviamo un errore, reindirizziamo a modificare azione (stiamo assumendo che il modulo abbia postato le informazioni sbagliate). Se non abbiamo riscontrato un errore, invia la richiesta al indice azione.

    Questo è tutto! Sono stati fatti.

    È possibile testare la funzionalità di rimozione riavviando il server, creando un nuovo fare elemento, facendo clic sul suo collegamento, quindi facendo clic sul pulsante "Rimuovi". Se hai fatto bene, dovresti tornare sulla pagina indice con quell'elemento rimosso.


    I prossimi passi

    Nel prossimo tutorial useremo il fantastico modulo mongodb-wrapper di http: //i.tv per persistere farein MongoDB. Con Geddy, sarà facile; tutto quello che dovremo cambiare è l'adattatore del modello.

    Se avete domande, si prega di lasciare un commento qui o aprire un problema su github.