Crearea unei aplicații listă Todo cu Node.js și Geddy

În acest tutorial de trei părți, vom fi scufundați adânc în crearea unei aplicații de gestionare a listelor în Node.js și Geddy. Aceasta este a doua parte a seriei, unde vom crea o aplicație de gestionare a listei simple.


Recapitulare

Ca o reîmprospătare rapidă, ultima dată când am instalat Node și Geddy, am generat o nouă aplicație și am învățat cum să pornim serverul. În acest tutorial ne vom baza pe ceea ce am făcut ultima oară, așa că asigurați-vă că ați terminat acest lucru înainte de a continua.


Generarea resurselor Todo

Geddy are un generator de resurse construit; acest lucru ne va permite să generăm automat un model, controler, vizualizări și rute pentru o anumită resursă. Aplicația noastră de listă va avea doar o singură resursă: a face. Pentru ao genera, doar CD în directorul aplicației (calea cd / to / your / todo_app) și fugi:

gaddy resource todo

Acum ar trebui să adăugați aceste fișiere în aplicația dvs.:

  • app / modele / todo.js
  • app / controlere / todos.js
  • app / views / Todos /
    • index.html.ejs
    • show.html.ejs
    • edit.html.ejs
    • add.html.ejs

Ta config / router.js ar trebui, de asemenea, să o anexăm:

router.resource ( 'todos');

Ce face totul

Dacă sunteți nou la MVC, toate acestea vă pot părea puțin cam descurajante. Nu vă faceți griji, este foarte simplu odată ce ați dat seama.

modele / todo.js: Acest fișier este locul unde ne vom defini a face model. Vom defini un număr de proprietăți pe care toate acestea le conțin a faceau. De asemenea, vom scrie câteva validări de date aici.

controlere / todos.js: Acest fișier este în cazul în care toate / Todos / rutele se termină. Fiecare acțiune în acest controler are un traseu corespunzător:

GET / todos / => index POST / todos / => creați GET / todos /: id => arătați PUT / todos /: id => actualizare DELETE / todos /: id => remove GET / todos / > adăugați GET / todos /: id / edit => editați

vizualizari / Todos /: Fiecare fișier de aici corespunde cu unul din OBȚINE rutele pe care vi le-am arătat mai sus. Acestea sunt șabloanele pe care le folosim pentru a genera capătul frontal al aplicației. Geddy utilizează EJS (JavaScript încorporat), deoarece este un limbaj de template. Ar trebui să pară familiar dacă ați folosit vreodată PHP sau ERB. Practic, puteți utiliza orice JavaScript pe care doriți în șabloanele dvs..

Obținerea unui sentiment pentru rute

Acum, că am generat o grămadă de cod, să verificăm că avem toate căile de care avem nevoie. Porniți din nou aplicația (geddy) și indicați browser-ul dvs. la http: // localhost: 4000 / todos. Ar trebui să vezi ceva de genul ăsta

Continuați și încercați asta pentru celălalt OBȚINE și rute:

  • http: // localhost: 4000 / todos / ceva
  • http: // localhost: 4000 / todos / add
  • http: // localhost: 4000 / todos / ceva / edita

Toate bune? Bine, să continuăm.


Crearea modelului Todo

În Geddy (și în majoritatea celorlalte cadre MVC), utilizați modele pentru a defini tipul de date cu care va funcționa aplicația dvs. Tocmai am generat un model pentru noi a faces, deci să vedem ce ne-a dat:

var Todo = funcție () // Câțiva comentați codul; // Unul mai comentat codul Todo = geddy.model.register ('Todo', Todo);

Modelele sunt destul de simple în Geddy. Noi doar creăm o nouă funcție de constructor pentru noi a faceși înregistrându-l ca model în geddy. Să definim câteva proprietăți pentru noi a faces. Ștergeți tot codul comentat și adăugați-l la funcția contructor:

var id: type: 'string', cerut: true, status: type: 'string', cerut : Adevărat ); ;

Al nostru a faces va avea un titlu, un id și o stare și toate cele trei vor fi necesare. Acum, să punem câteva validări pentru noi a faces.

var id: type: 'string', cerut: true, status: type: 'string', cerut : Adevărat ); this.validatesPresent ( 'titlu'); this.validatesLength ("titlu", min: 5); this.validatesWithFunction ('status', funcția (status) return status == 'open' || status == 'done';); ;

Validăm că titlul este prezent, că titlul are o lungime minimă de 5 caractere și că folosim o funcție pentru a valida că statutul este fie deschis sau Terminat. Există câteva funcții de validare care sunt construite, continuați și verificați proiectul pe http://github.com/mde/geddy pentru a afla mai multe despre ele.


Crearea adaptorului de model Todo

Acum, când am creat modelul todo, putem crea undeva pentru a stoca modelele noastre. În scopul acestui tutorial, vom păstra datele în memorie. Vom suspenda o gamă de todos din lumea noastră geddy obiecte pentru a lipi datele. În următoarea parte a acestei serii, vom începe să le obținem într-o bază de date.

Editarea fișierului dvs. init.js

Deschide-ți config / init.js fişier. Tot ce ar trebui să fie acolo acum este un manipulator excepțional de excepție la nivel mondial:

// adăugați un handler de excepție uncaught în medii prod-like dacă (geddy.config.environment! = 'Development') process.addListener ('uncaughtException', funcția (err) geddy.log.error (JSON.stringify ));); 

Imediat după acest bloc de cod, hai să ne agățăm matricea geddy global:

geddy.todos = [];

Acolo, acum avem un loc pentru a ne depozita a faces. Amintiți-vă că aceasta este în memoria aplicației dvs., astfel încât va dispărea atunci când reporniți serverul.

Crearea adaptorului de model

Un model-adaptor oferă baza Salvați, elimina, sarcină, și toate metode de care are nevoie un model. Sursa noastră de date este destul de simplă (doar o matrice!), Așa că scrierea adaptorului nostru de model ar trebui să fie destul de simplă.

Creați un director în lib denumit model_adapters și creați un fișier în lib / model_adapters denumit todo.js. Să deschidem acel fișier și să adăugăm un cod de boilerplate:

var Todo = nou (funcția () ) (); exports.Todo = Todo;

Tot ceea ce facem aici este crearea unui nou obiect gol, care să fie exportat în orice scop, care necesită acest fișier. Dacă doriți să aflați mai multe despre modul în care funcționează metoda Node, acest articol are o imagine de ansamblu destul de bună. În acest caz, ale noastre init.js fișierul va face necesarul.

Solicitați adaptorul de model în init.js

Așa că am creat un nou obiect adaptor Todo. E destul de stearpă acum, dar vom ajunge la asta în curând. Pentru moment, va trebui să ne întoarcem la init.js și să adăugăm un cod astfel încât să fie încărcat în aplicația noastră atunci când pornește. După geddy.todos = []; în config / init.js adăugați aceste două linii:

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

Am creat un obiect gol pentru modelul adaptor și am adăugat adaptorul de model Todo pe el.


Salvarea Todos

Acum, când avem modelul și adaptorul nostru de model, putem începe în logica aplicației. Să începem cu adăugarea de articole în lista noastră de lucru.

Editați metoda de salvare de pe adaptor pentru a salva o instanță todo

Când lucrați cu date, primul loc pe care ar trebui să-l faceți este adaptorul de model. Trebuie să putem salva o instanță a modelului nostru Todo în matricea noastră geddy.todos. Deci, deschide-te lib / model_adapters / todo.js și adăugați o metodă de salvare:

var Todo = nou (funcția () this.save = funcția (todo, opts, callback) if (typeof callback! = 'function') callback = function; todos.push (todo); retur apel invers (null, todo);) ();

Tot ce trebuie să facem este să setăm proprietatea salvată a instanței la adevărat și să împingem elementul în matricea geddy.todos. În Nod, este mai bine să faceți toate intrările / ieșirile într-un mod ne-blocabil, deci este o idee bună să obțineți obiceiul de a utiliza apeluri de apel pentru a transmite date în jur. Pentru acest tutorial nu contează atât de mult, dar mai târziu când începem lucruri perseverente, va veni la îndemână. Veți observa că ne-am asigurat că apelul este o funcție. Dacă nu facem acest lucru și vom folosi salvați fără apel invers, am obține o eroare. Acum, să mergem la acțiunea de creare a controlorului.

Editați acțiunea de creare pentru a salva o instanță todo

Continuați și aruncați o privire la crea acțiune în app / controlere / todos.js:

this.create = funcția (req, resp, params) // Salvați resursa, apoi afișați pagina de index this.redirect (controller: this.name); ;

Destul de simplu, nu? Geddy ți-a stîngiat-o. Deci haideți să o modificăm puțin:

Aceasta este o functie (req, resp, params) var self = aceasta, todo = geddy.model.Todo.create (title: params.title, id: geddy.string.uuid '); todo.save (funcția (err, date) if (err) params.errors = err; self.transirect ('add'); ; ;

În primul rând, vom crea o nouă instanță a modelului Todo cu geddy.model.Todo.create, trecând în titlul pe care îl va afișa formularul nostru și setând valorile implicite pentru id și stare.

Apoi numim metoda de salvare pe care am creat-o pe adaptorul de model și redirecționăm utilizatorul înapoi la ruta / todos. Dacă nu a trecut validarea sau am primit o eroare, folosim controlerul transfer metoda de transferare a solicitării înapoi la adăuga acțiune.

Editați add.html.ejs

Acum este momentul să configurați șablonul de adăugare. Aruncăm o privire la app / views / Todos / add.html.ejs, ar trebui să arate astfel:

params

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

Nu vom avea nevoie de asta

    pentru cazul nostru de utilizare, așa că să scăpăm de el deocamdată. Fă-ți add.html.ejs arata astfel:

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

    Un intro la paralele

    Paralele vă oferă o modalitate ușoară de a partaja codul între șabloanele dvs..

    Veți observa că folosim parțial acest șablon. Paralele vă oferă o modalitate ușoară de a partaja codul între șabloanele dvs. Modelele noastre de adăugare și editare folosesc același formular, așadar să creăm parțial acest formular. Creați un fișier nou în vizualizari / Todos / director numit _form.html.ejs. Utilizăm o subliniere pentru a afla dacă acest șablon este parțial. Deschideți-l și adăugați în acest cod:

    <% 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 %>
    stare
    <% %>
    Eliminați <% %>

    Whoa, asta e mult cod acolo! Să vedem dacă putem trece prin ea. Din moment ce două șabloane diferite vor folosi acest lucru parțial, trebuie să ne asigurăm că formularul pare corect în ambele. Majoritatea acestui cod este de fapt boilerplate de pe bootstrap-ul Twitter. Este ceea ce permite acestei aplicații să arate atât de bine chiar de pe lilieci (și pe dispozitivele mobile prea!).

    Pentru a face ca această aplicație să arate chiar mai bine, puteți utiliza fișierul CSS furnizat în descărcarea aplicației demo.

    Primul lucru pe care l-am făcut a fost stabilirea unor variabile pe care să le putem folosi. În adăuga acțiunea pe care o parcurgem params obiecte în jos până la șablon în răspunde apel de metodă. Acest lucru ne oferă câteva lucruri - ne spune ce controler și acțiune această solicitare a fost direcționată și ne dă parametrii de interogare care au fost transmiși în url. Am creat isUpdate variabilă pentru a vedea dacă suntem în prezent în acțiunea de actualizare și apoi am creat alte câteva variabile pentru a ne ajuta să ne curățăm codul de vizualizare.

    De acolo, tot ce am făcut a fost să facem o formă. Dacă suntem în legătură cu acțiunea de adăugare, facem ca formularul să fie așa cum este. Dacă suntem în acțiunea de editare, vom completa formularul pentru a permite utilizatorului să actualizeze câmpurile.

    Observați că formularul va trimite a POST cererea către / Todos / cu _method = PUT parametru. Geddy utilizează parametrul de suprascriere a metodei standard pentru a vă permite să trimiteți A PUNE și ȘTERGE solicită browser-ul fără a fi nevoie să utilizeze JavaScript. (cel puțin în partea din față!)

    Ultimul mic detaliu pe care trebuie să ne uităm este acela că butonul "Elimină". Folosim html5 formaction să modifice acțiunea pentru acest formular. Veți observa că acest buton este formaction trimite un a POST solicitați până la / Todos /: id ruta cu a _method = ȘTERGE parametru. Acest lucru va afecta elimina acțiune pe controler, la care vom ajunge mai târziu.

    Reporniți serverul (geddy) și vizitați http: // localhost: 4000 / todos / add pentru a vedea șablonul în acțiune. Creați un element de realizat în timp ce sunteți la el.


    Afișați toate Todos

    Acum, că avem elemente de intrare ale utilizatorilor care doresc să fie adăugate în matricea geddy.todos, ar trebui să le menționăm undeva. Să începem pe toate în adaptorul de model.

    Editați toate metodele de pe adaptor pentru a afișa toate todulele

    Să ne deschidem lib / model_adapters / todo.js din nou și adăugați un toate metodele de mai sussalvați "metoda:

    this.all = funcția (apel invers) callback (null, geddy.todos); 

    Aceasta este probabil cea mai simplă metodă de adaptare a modelului pe care o vom crea astăzi, tot ceea ce face este acceptarea unui apel invers și apelarea cu o eroare (care este întotdeauna nulă pentru moment, vom actualiza această metodă în următorul tutorial), și geddy.todos.

    Editați acțiunea index pentru a afișa toate todos

    Deschide /app/controllers/todos.js din nou și să aruncați o privire la index acțiune. Ar trebui să arate ceva de genul:

    this.index = funcția (req, resp, params) this.respond (params: params); ;

    Această parte este foarte simplu, noi doar folosim toate metoda pe care tocmai am definit-o pe adaptorul-model pentru a obține toate a faces și le face:

    this.index = funcția (req, resp, params) var self = aceasta; geddy.model.adapter.Todo.all (funcția (err, todos) auto.respond (params: params, todos: todos);); ;

    Asta e pentru controlor, acum pe vedere.

    Editați index.html.ejs

    Aruncați o privire la /app/views/todos/index.html.ejs, ar trebui să arate astfel:

    params

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

    Arată mult ca șablonul add.html.ejs nu-l face. Din nou, nu vom avea nevoie de parcela de boilerplate aici, deci ia-o afară și face ca șablonul dvs. index.html.ejs să arate astfel:

    Pentru a face lista

    Creați un nou De făcut

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

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

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

    <% %> <% %>

    Aceasta este, de asemenea, destul de simplă, dar de data aceasta avem o buclă în șablonul nostru. În antetul acolo am adăugat un buton pentru a adăuga doze noi. În interiorul buclei generăm un rând pentru fiecare a face, afișându-i titlul (ca și link către el Editați | × pagina) și starea sa.

    Pentru a le verifica, accesați http: // localhost: 4000 / todos.


    Editarea unei melodii Todo

    Acum că avem o legătură cu Editați | × ar trebui, probabil, să o facem să funcționeze!

    Creați o metodă de încărcare în adaptorul de model

    Deschideți din nou adaptorul de model (/lib/model_adapters/todo.js). Vom adăuga a sarcină astfel încât să putem încărca un anumit a face și folosiți-o în pagina noastră de editare. Nu contează unde îl adăugați, dar pentru moment să o punem între toate și metoda Salvați metodă:

    this.load = funcția (id, callback) pentru (var i în geddy.todos) if (geddy.todos [i] .id == id) retur apel invers (null, geddy.todos [i]);  apel invers (message: "Nu se găsește", null); ;

    Această metodă de încărcare are un id și un apel invers. Se bate prin elementele din geddy.todos și verifică dacă elementul curent este id se potrivește cu cel trecut id. În caz contrar, acesta apelează apelul invers, trecând a face înapoi. Dacă nu găsește o potrivire, el apelează apelul cu o eroare. Acum trebuie să folosim această metodă în acțiunea show-ului controlerului todos.

    Modificați acțiunea de editare pentru a găsi o sumă licitată

    Deschide-ți Todos controler din nou și să aruncați o privire la ea este Editați | × acțiune. Ar trebui să arate ceva de genul:

    this.edit = funcția (req, resp, params) this.respond (params: params); ;

    Să folosim metoda de încărcare pe care tocmai am creat-o:

    this.edit = funcția (req, resp, params) var self = aceasta; geddy.model.Todo.load (params.id, funcția (err, todo) auto.respond (params: params, todo: todo);); ;

    Tot ceea ce facem aici este încărcarea todo-ului și trimiterea acestuia la șablonul care urmează să fie redat. Deci, să aruncăm o privire la șablon.

    Editați edit.html.ejs

    Deschide /app/views/todos/edit.html.ejs. Încă o dată nu vom avea nevoie de boilerplate params, așa că să-l eliminăm. Fă-ți edit.html.ejs arata astfel:

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

    Acest lucru ar trebui să pară foarte asemănător cu add.html.ejs dosar pe care tocmai l-am editat. Veți observa că trimitem un mesaj a face obiectează atât parțial, cât și paramuri de data aceasta. Lucrul cool este că, din moment ce am scris deja parțial, este tot ceea ce trebuie să facem pentru ca pagina de editare să apară corect.

    Reporniți serverul, creați un nou a face și faceți clic pe link pentru a vedea cum funcționează aceasta. Acum, să facem ca acel buton de actualizare să funcționeze!

    Editați metoda de salvare în adaptorul de model

    Deschideți din nou adaptorul de model și găsiți Salvați metodă. vom adăuga un pic la ea pentru a putea salva peste existente a faces. Faceți-o să arate astfel:

    this.save = funcția (todo, opts, callback) if (tip callback! = 'funcția') callback = funcția () ;  var todoErrors = null; pentru (var i în geddy.todos) // dacă este deja acolo, salvați-l dacă (geddy.todos [i] .id == todo.id) geddy.todos [i] = todo; todoErrors = geddy.model.Todo.create (todo) .errors; retur apel invers (todoErrors, todo);  todo.saved = true; geddy.todos.push (todo); retur apel invers (null, todo); 

    Aceasta bate peste toate todo's in geddy.todos și dacă id este deja acolo, înlocuiește asta a face cu noul a face instanță. Facem câteva lucruri aici pentru a ne asigura că validările noastre lucrează la actualizare și la crearea - pentru a face acest lucru trebuie să tragem erori proprietate off de o instanță model nou și să treacă că înapoi în apel invers. Dacă a trecut validările, va fi doar nedefinită și codul nostru o va ignora. Dacă nu a trecut, todoErrors va fi o serie de erori de validare.

    Acum, că avem așa ceva, să lucrăm la controlorul nostru Actualizați acțiune.


    Editați acțiunea de actualizare pentru a găsi o taxă, modificați starea și salvați-o

    Continuați și deschideți din nou controlerul și găsiți acțiunea "actualizare", ar trebui să arate ceva de genul:

    this.update = funcția (req, resp, params) // Salvați resursa, apoi afișați pagina elementului this.redirect (controller: this.name, id: params.id); ;

    Veți dori să o editați pentru a arăta astfel:

    this.update = funcția (req, resp, params) var self = aceasta; geddy.model.adapter.Todo.load (params.id, funcția (err, todo) todo.status = params.status; todo.title = params.title; todo.save (funcție (err, date) if err) params.errors = err; auto.transfer ("editați"); altceva self.redirect (controller: self.name););); ;

    Ceea ce facem aici este încărcarea solicitată a face, editând unele dintre proprietățile sale și salvând a face din nou. Codul pe care tocmai l-am scris în adaptorul de model ar trebui să se ocupe de restul. Dacă vom obține o eroare înapoi, înseamnă că noile proprietăți nu au trecut validarea, așa că vom transfera solicitarea înapoi la Editați | × acțiune. Dacă nu am revenit la o eroare, vom redirecționa solicitarea înapoi la index acțiune.

    Mergeți și încercați. Reporniți serverul, creați un nou a face, faceți clic pe legătura de editare a acestuia, modificați statusul la Terminat, și vezi că este actualizat în index. Dacă doriți să verificați funcționarea validaturilor, încercați să schimbați titlu la ceva mai mic de 5 caractere.

    Acum, hai să folosim butonul "Elimină".


    Eliminarea unui Todo

    Până acum avem o aplicație de lucru pentru a face lista, dar dacă începeți să o utilizați pentru o vreme, va fi dificil să găsiți a face element pe care îl căutați în pagina index. Să facem lucrul cu butonul "Eliminați" astfel încât să putem păstra lista noastră frumoasă și scurtă.

    Creați o metodă de eliminare în adaptorul de model

    Să ne deschidem din nou modelul nostru de adaptare, de data aceasta vom dori să adăugăm o elimina acolo. Adăugați acest drept după Salvați metodă:

    this.remove = funcția (id, callback) if (typeof callback! = 'funcția') callback = funcția () ;  pentru (var i în geddy.todos) if (geddy.todos [i] .id == id) geddy.todos.splice (i, 1); retur apel invers (null);  retur apel invers (message: "Nu se găsește"); 

    Aceasta este destul de simplă, ar trebui să arate mult ca metoda de încărcare. Acesta trece prin toate a faces in geddy.todos pentru a găsi id pe care îl căutăm. Apoi splice elementul din matrice și cheamă apelul invers. Dacă nu se găsește în matrice, acesta apelează apelul cu o eroare.

    Să folosim asta la controlorul nostru acum.

    Editați acțiunea de eliminare

    Deschideți din nou controlerul și trageți elimina acțiune. Ar trebui să arate ceva de genul:

    this.remove = funcția (req, resp, params) this.respond (params: params); ;

    Editați-l pentru a face acest lucru:

    this.remove = funcția (req, resp, params) var self = aceasta; geddy.model.adapter.Todo.remove (params.id, funcția (err) if (err) params.errors = err; self.transfer ("editați"); .Nume);  ); 

    Noi trecem id pe care le-am primit de la params în postul de formular în elimina metoda pe care tocmai am creat-o. Dacă revenim la o eroare, redirecționăm înapoi la Editați | × (presupunem că formularul a trimis informații greșite). Dacă nu am primit o eroare înapoi, trebuie doar să trimiteți cererea către index acțiune.

    Asta e! Au fost efectuate.

    Puteți testa caracteristica de eliminare prin restartarea serverului, creând un nou a face faceți clic pe link-ul său, apoi faceți clic pe butonul "Eliminați". Dacă ați făcut-o corect, ar trebui să vă întoarceți la pagina indexului cu acel element eliminat.


    Următorii pași

    În tutorialul următor vom folosi un modul minunat de împachetare a http: //i.tv pentru a persista a faceîn MongoDB. Cu Geddy, acest lucru va fi ușor; tot ce trebuie să schimbăm este adaptorul de model.

    Dacă aveți întrebări, vă rugăm să lăsați un comentariu aici sau să deschideți o problemă pe github.

    Cod