In deze driedelige tutorial duiken we diep in het maken van een to-do list management-app in Node.js en Geddy. Dit is het tweede deel in de serie, waarin we een eenvoudig te doen lijstbeheer-app zullen maken.
Als een snelle opfriscursus hebben we Node en Geddy voor het laatst geïnstalleerd, een nieuwe app gemaakt en geleerd hoe de server moet worden opgestart. In deze zelfstudie bouwen we verder op wat we de vorige keer hebben gedaan. Zorg er dus voor dat je die hebt voltooid voordat je verdergaat.
Geddy heeft een ingebouwde brongenerator; dit zal ons in staat stellen om automatisch een model, controller, views en routes voor een specifieke resource te genereren. Onze takenlijst-app heeft maar één bron: Te doen
. Om het te genereren, gewoon CD
in de directory van uw app (cd-pad / naar / uw / todo_app
) en loop:
geddy resource todo
U moet deze bestanden nu aan uw app toevoegen:
Jouw config / router.js
moet dit ook als bijlage hebben:
router.resource ( 'todos');
Als je nieuw bent bij MVC lijkt dit allemaal een beetje intimiderend voor je. Maar maak je geen zorgen, het is heel eenvoudig als je er eenmaal achter bent.
modellen / todo.js: Dit bestand is waar we onze zullen definiëren Te doen
model. We zullen een aantal eigenschappen definiëren die dat allemaal zijn Te doen
hebben. We zullen hier ook enkele gegevensvalidaties schrijven.
controllers / todos.js: Dit bestand is waar alle / Todos /
routes eindigen. Elke actie in deze controller heeft een bijbehorende route:
GET / todos / => index POST / todos / => create GET / todos /: id => show PUT / todos /: id => update DELETE / todos /: id => remove GET / todos /: id / add = > voeg GET / todos /: id / edit => edit toe
views / todos /: Elk bestand hier komt overeen met een van de KRIJGEN
routes die we je hierboven hebben laten zien. Dit zijn de sjablonen die we gebruiken om de voorkant van de app te genereren. Geddy maakt gebruik van EJS (ingebed JavaScript) omdat het sjableltaal is. Het moet er bekend uitzien als je ooit PHP of ERB hebt gebruikt. Kortom, u kunt elk JavaScript dat u wilt gebruiken in uw sjablonen.
Nu we een aantal codes hebben gegenereerd, laten we controleren of we alle routes hebben die we nodig hebben. Start de app opnieuw (Geddy
) en wijs uw browser naar http: // localhost: 4000 / todos. Je zou zoiets moeten zien
Ga je gang en probeer dat voor de ander KRIJGEN
routes ook:
Alles goed? Oké, laten we doorgaan.
In Geddy (en de meeste andere MVC-frameworks), gebruik je modellen om het soort gegevens te definiëren waarmee je app zal werken. We hebben zojuist een model voor onze gegenereerd Te doen
s, dus laten we eens kijken wat dat ons gaf:
var Todo = function () // Some commented out code; // Een beetje meer commentaarcode Todo = geddy.model.register ('Todo', Todo);
Modellen zijn vrij eenvoudig in Geddy. We maken gewoon een nieuwe constructorfunctie voor onze Te doen
s en registreer het als een model in geddy. Laten we enkele eigenschappen voor onze definiëren Te doen
s. Verwijder alle uitgelichte code en voeg deze toe aan de contructorfunctie:
var Todo = function () this.defineProperties (title: type: 'string', required: true, id: type: 'string', required: true, status: type: 'string', vereist : true); ;
Onze Te doen
s heeft een titel, een id en een status en alle drie zijn vereist. Laten we nu een aantal validaties instellen voor onze Te doen
s.
var Todo = function () this.defineProperties (title: type: 'string', required: true, id: type: 'string', required: true, status: type: 'string', vereist : true); this.validatesPresent (titel); this.validatesLength ('title', min: 5); this.validatesWithFunction ('status', functie (status) retourstatus == 'open' || status == 'done';); ;
We valideren dat de titel aanwezig is, dat de titel een minimale lengte van 5 tekens heeft en we gebruiken een functie om te valideren dat de status ofwel Open
of gedaan
. Er zijn nogal wat valitation-functies ingebouwd, ga je gang en bekijk het project op http://github.com/mde/geddy voor meer informatie over hen.
Nu we ons todo-model hebben opgezet, kunnen we ergens een plek maken om onze modellen op te slaan. Ten behoeve van deze zelfstudie bewaren we de gegevens gewoon in het geheugen. We hangen een todos-array af van onze global Geddy
object om de gegevens in te bewaren. In het volgende deel van deze serie zullen we beginnen deze vast te houden in een database.
Open je config / init.js
het dossier. Alles wat er nu zou moeten zijn, is een globale niet-afgevangen uitzonderingsbehandelaar:
// Voeg niet-afgevangen-uitzondering-handler toe in prod-achtige omgevingen als (geddy.config.environment! = 'Development') process.addListener ('uncaughtException', function (err) geddy.log.error (JSON.stringify (err) )););
Direct na dat codeblok laten we onze array van de Geddy
globaal:
geddy.todos = [];
Daar hebben we nu een plek om onze te bewaren Te doen
s. Houd er rekening mee dat dit zich in het geheugen van uw toepassing bevindt. Het verdwijnt dus als u de server opnieuw opstart.
Een model-adapter biedt de basis opslaan
, verwijderen
, laden
, en allemaal
methoden die een model nodig heeft. Onze gegevensbron is vrij eenvoudig (slechts een array!), Dus het schrijven van onze modeladapter zou ook vrij eenvoudig moeten zijn.
Maak een map aan in lib
riep model_adapters
en maak een bestand aan lib / model_adapters
riep todo.js
. Laten we dat bestand openen en wat boilerplate code toevoegen:
var Todo = nieuw (function () ) (); exporteert. Tood = Taken;
Het enige dat we hier doen, is het instellen van een nieuw leeg object dat geëxporteerd moet worden naar wat uiteindelijk dit bestand vereist. Als u meer wilt weten over hoe de methode van Node werkt, heeft dit artikel een goed overzicht. In dit geval onze init.js
bestand zal het vereiste doen.
Daarom hebben we een nieuw Todo-model-adapterobject opgezet. Het is op dit moment behoorlijk kaal, maar daar komen we snel bij. Voor nu moeten we teruggaan naar init.js en een code toevoegen, zodat deze bij het opstarten in onze app wordt geladen. Na de geddy.todos = [];
in config / init.js
voeg deze twee regels toe:
geddy.model.adapter = ; geddy.model.adapter.Todo = require (process.cwd () + '/lib/model_adapters/todo').Todo;
We hebben een leeg model-adapterobject gemaakt en de Todo-modeladapter eraan toegevoegd.
Nu we onze model- en modeladapter op hun plaats hebben, kunnen we beginnen aan de app-logica. Laten we beginnen met het toevoegen van taken aan onze takenlijst.
Wanneer u met gegevens werkt, moet u eerst de modeladapter gebruiken. We moeten een exemplaar van ons Todo-model kunnen opslaan in onze geddy.todos-array. Dus open lib / model_adapters / todo.js
en voeg een opslagmethode toe:
var Todo = new (function () this.save = function (todo, opts, callback) if (typeof callback! = 'function') callback = function () ; todo.saved = true; geddy. todos.push (todo); terugbellen (null, todo);) ();
Het enige wat we moeten doen is de eigenschap van het exemplaar instellen op true en het item in de array geddy.todos duwen. In Node is het het beste om alle I / O op een niet-blokkerende manier te doen, dus het is een goed idee om de gewoonte aan te nemen om callbacks te gebruiken om gegevens door te geven. Voor deze zelfstudie maakt het niet zoveel uit, maar als we later dingen blijven doen, zal het van pas komen. U zult merken dat we ervoor hebben gezorgd dat de callback een functie is. Als we dat niet doen en opslaan gebruiken zonder terug te bellen, krijgen we een foutmelding. Laten we nu doorgaan naar de actie voor het maken van de controller.
Ga je gang en kijk eens naar de creëren
actie in app / controllers / todos.js
:
this.create = function (req, resp, params) // Sla de resource op en geef indexpagina this.redirect weer (controller: this.name); ;
Best simpel, toch? Geddy heeft het voor je uitgepraat. Dus laten we het een beetje aanpassen:
this.create = function (req, resp, params) var self = this, todo = geddy.model.Todo.create (title: params.title, id: geddy.string.uuid (10), status: 'open '); todo.save (functie (err, data) if (err) params.errors = err; self.transfer ('add'); else self.redirect (controller: self.name);) ; ;
Eerst maken we een nieuw exemplaar van het Todo-model met geddy.model.Todo.create
, het doorgeven van de titel die ons formulier naar ons zal posten, en het instellen van de standaardinstellingen voor het ID en de status.
Vervolgens noemen we de opslagmethode die we hebben gemaakt op de modeladapter en leiden we de gebruiker terug naar de / todos-route. Als het de validatie niet heeft doorstaan of als er een fout optreedt, gebruiken we de controller overdracht
methode om het verzoek terug te sturen naar de toevoegen
actie.
Nu is het tijd voor ons om de sjabloon toe te voegen. Kijk eens naar app / views / todos / add.html.ejs
, het zou er zo uit moeten zien:
params
<% for (var p in params) %>
- <%= p + ': ' + params[p]; %>
<% %>
Dat hebben we niet nodig
voor onze use case, dus laten we er vanaf nu van af. Maak jouw add.html.ejs
er uitzien als dit:
<%= partial('_form', params: params); %>
Partials bieden u een eenvoudige manier om code te delen tussen uw sjablonen.
U zult merken dat we een gedeeltelijke in deze sjabloon gebruiken. Partials bieden u een eenvoudige manier om code te delen tussen uw sjablonen. Onze sjablonen voor toevoegen en bewerken gaan allebei hetzelfde formulier gebruiken, dus laten we dit formulier nu gedeeltelijk maken. Maak een nieuw bestand in de views / todos /
map genoemd _form.html.ejs
. We gebruiken een onderstrepingsteken om eenvoudig te bepalen of deze sjabloon gedeeltelijk is. Open het en voeg deze code toe:
<% 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; %>
Whoa, dat is veel code daar! Laten we kijken of we er doorheen kunnen lopen. Aangezien er twee verschillende sjablonen zijn die dit deel gaan gebruiken, moeten we ervoor zorgen dat het formulier er in beide goed uitziet. Het grootste deel van deze code is eigenlijk boilerplate van Twitter's Bootstrap. Dit is wat ervoor zorgt dat deze app er meteen goed uitziet (en ook op mobiele apparaten!).
Om deze app er nog beter uit te laten zien, kunt u het CSS-bestand gebruiken dat is meegeleverd in de download van de demo-app.
Het eerste dat we deden, was een aantal variabelen instellen die we konden gebruiken. In de toevoegen
actie die we doorstaan a params
object naar beneden naar de sjabloon in de reageren
method call. Dit geeft ons een paar dingen - het vertelt ons naar welke controller en actie dit verzoek is gerouteerd en geeft ons alle queryparameters die in de URL zijn doorgegeven. We hebben de isUpdate
variabele om te zien of we momenteel bezig zijn met de updateactie en vervolgens stellen we nog enkele variabelen in om onze weergavecode op te schonen.
Vanaf daar was alles wat we deden een formulier maken. Als we de actie toevoegen, geven we het formulier gewoon weer zoals het is. Als we de bewerkingsactie uitvoeren, vullen we het formulier in om de gebruiker de velden te laten bijwerken.
Merk op dat het formulier een verzendt POST
verzoek aan de / Todos /
met een _method = PUT
parameter. Geddy gebruikt de standaardmethode negeerparameter om u te laten verzenden LEGGEN
en DELETE
vraagt vanuit de browser op zonder JavaScript te gebruiken. (aan de voorkant tenminste!)
Het laatste kleine detail dat we moeten bekijken is die knop "Verwijderen". We gebruiken html5's formaction
attribuut om de actie voor dit formulier te wijzigen. Je zult merken dat deze knop is formaction
verzendt een POST
verzoek tot de / Todos /: id
route met een _method = WISSEN
parameter. Dit raakt de verwijderen
actie op de controller, die we later zullen zien.
Start uw server opnieuw op (Geddy
) en bezoek http: // localhost: 4000 / todos / add om uw sjabloon in actie te zien. Maak een To Do-item terwijl je bezig bent.
Nu we To Do-items van gebruikersinvoer hebben toegevoegd aan onze geddy.todos-array, moeten we ze waarschijnlijk ergens vermelden. Laten we beginnen op de allemaal
methode in de model-adapter.
Laten we openen lib / model_adapters / todo.js
nogmaals en voeg een toe alle methoden recht boven de
opslaan 'methode:
this.all = function (callback) callback (nul, geddy.todos);
Dit is waarschijnlijk de eenvoudigste model-adapter methode die we vandaag zullen creëren, het enige dat het doet is een callback accepteren en het een fout noemen (wat altijd null is, we zullen deze methode in de volgende tutorial upgraden), en geddy.todos
.
Doe open /app/controllers/todos.js
nogmaals en kijk eens naar de inhoudsopgave
actie. Het zou er ongeveer zo uit moeten zien:
this.index = function (req, resp, params) this.respond (params: params); ;
Dit deel is heel eenvoudig, we gebruiken alleen het allemaal
methode die we zojuist hebben gedefinieerd op de model-adapter om alle te krijgen Te doen
s en render ze:
this.index = function (req, resp, params) var self = this; geddy.model.adapter.Todo.all (function (err, todos) self.respond (params: params, todos: todos);); ;
Dat is het voor de controller, nu op het uitzicht.
Neem een kijkje op /app/views/todos/index.html.ejs, het zou er als volgt uit moeten zien:
params
<% for (var p in params) %>
- <%= p + ': ' + params[p]; %>
<% %>
Lijkt veel op de template add.html.ejs niet. Nogmaals, we hebben de params boilerplate hier niet nodig, dus haal dat eruit en laat je index.html.ejs-sjabloon er als volgt uitzien:
<% if (todos && todos.length) %> <% for (var i in todos) %>Te doen lijst
Maak een nieuwe taak<% %> <% %>/ Bewerken "><%= todos[i].title; %>
<%= todos[i].status; %>
Deze is ook vrij eenvoudig, maar deze keer hebben we een lus in onze sjabloon. In de header daar hebben we een knop toegevoegd om nieuwe taken toe te voegen. In de loop genereren we een rij voor elk Te doen
, weergeven van de titel (als een link naar die is) Bewerk
pagina) en de status ervan.
Ga naar http: // localhost: 4000 / todos voor meer informatie.
Nu hebben we een link naar de Bewerk
pagina, we moeten het waarschijnlijk laten werken!
Open uw modeladapter opnieuw (/lib/model_adapters/todo.js
). We gaan toevoegen in a laden
methode zodat we een specifieke kunnen laden Te doen
en gebruik het op onze bewerkpagina. Het maakt niet uit waar je het toevoegt, maar laat het nu tussen de allemaal
methode en de opslaan
methode:
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); ;
Deze laadmethode neemt een id en een callback. Het loopt door de items in geddy.todos
en controleert om te zien of het huidige item is ID kaart
komt overeen met de doorgegeven ID kaart
. Als dit het geval is, wordt de callback aangeroepen en wordt de Te doen
item terug. Als het geen overeenkomst vindt, roept het de callback met een fout op. Nu moeten we deze methode gebruiken in de showactie van de todos-controller.
Open je todos
controller opnieuw en kijk eens naar het is Bewerk
actie. Het zou er ongeveer zo uit moeten zien:
this.edit = function (req, resp, params) this.respond (params: params); ;
Laten we de laadmethode gebruiken die we zojuist hebben gemaakt:
this.edit = function (req, resp, params) var self = this; geddy.model.Todo.load (params.id, function (err, todo) self.respond (params: params, todo: todo);); ;
Het enige wat we hier doen is het laden van de taak en het verzenden naar de sjabloon die moet worden weergegeven. Laten we de sjabloon eens bekijken.
Doe open /app/views/todos/edit.html.ejs
. Nogmaals, we zullen de params boilerplate niet nodig hebben, dus laten we het verwijderen. Maak jouw edit.html.ejs
er uitzien als dit:
<%= partial('_form', params: params, todo: todo); %>
Dit zou er ongeveer hetzelfde uit moeten zien te zien als de add.html.ejs
bestand dat we zojuist hebben bewerkt. U zult merken dat we een Te doen
bezwaar tot de gedeeltelijke evenals de params deze keer. Het leuke is, omdat we de gedeeltelijke tekst al hebben geschreven, dit is alles wat we moeten doen om ervoor te zorgen dat de bewerkpagina correct wordt weergegeven.
Start de server opnieuw op, maak een nieuwe aan Te doen
en klik op de link om te zien hoe dit werkt. Laten we nu die updateknop werken!
Open opnieuw de model-adapter en vind de opslaan
methode. we gaan er een beetje aan toevoegen, zodat we kunnen besparen over het bestaande Te doen
s. Laat het er zo uitzien:
this.save = functie (todo, opts, callback) if (typeof callback! = 'function') callback = function () ; var todoErrors = null; for (var i in geddy.todos) // als het er al is, sla het op als (geddy.todos [i] .id == todo.id) geddy.todos [i] = todo; todoErrors = geddy.model.To.maken (todo) .errors; return callback (todoErrors, todo); todo.saved = true; geddy.todos.push (todo); return callback (null, todo);
Dit lus over alle todo's geddy.todos
en als het ID kaart
is er al, het vervangt dat Te doen
met het nieuwe Te doen
aanleg. We doen hier wat dingen om ervoor te zorgen dat onze validaties zowel werken aan update als aan het maken - om dit te doen moeten we de fouten
eigenschap van een nieuwe modelinstantie en geef die terug in de callback. Als het validaties heeft doorstaan, is het gewoon ongedefinieerd en negeert onze code het. Als het niet is geslaagd, todoErrors
zal een reeks validatiefouten zijn.
Nu dat op zijn plaats is, laten we aan onze controller werken bijwerken
actie.
Ga je gang en open de controller opnieuw en vind de 'update'-actie, het zou er ongeveer zo uit moeten zien:
this.update = function (req, resp, params) // Sla de resource op en toon dan de itempagina this.redirect (controller: this.name, id: params.id); ;
Je zult het willen bewerken om het er zo uit te laten zien:
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););); ;
Wat we hier doen, is het laden van het gevraagde Te doen
, een aantal van zijn eigenschappen bewerken en de Te doen
nog een keer. De code die we zojuist in de model-adapter hebben geschreven zou de rest moeten behandelen. Als we een foutmelding krijgen, betekent dit dat de nieuwe eigenschappen niet zijn gevalideerd, dus we zullen het verzoek terugsturen naar de Bewerk
actie. Als we geen foutmelding hebben ontvangen, leiden we het verzoek gewoon door naar het inhoudsopgave
actie.
Ga je gang en probeer het uit. Start de server opnieuw op, maak een nieuwe aan Te doen
, klik op de bewerkingslink, verander de status in gedaan
, en zie dat het wordt bijgewerkt in de inhoudsopgave
. Als u wilt controleren of uw validaties werken, probeert u de titel
tot iets korter dan 5 tekens.
Laten we nu die knop "Verwijderen" gebruiken.
Inmiddels hebben we een werkende takenlijst-applicatie, maar als je het een tijdje gebruikt, zal het moeilijk worden om de Te doen
item dat u zoekt op die indexpagina. Laten we ervoor zorgen dat de knop "Verwijderen" werkt, zodat we onze lijst mooi en kort kunnen houden.
Laten we onze model-adapter opnieuw openen, deze keer willen we een toevoegen verwijderen
methode daar. Voeg dit toe direct na de opslaan
methode:
this.remove = function (id, callback) if (typeof callback! = 'function') callback = function () ; voor (var i in geddy.todos) if (geddy.todos [i] .id == id) geddy.todos.splice (i, 1); return callback (nul); return callback (message: "To Do not found");
Deze is vrij eenvoudig, het zou veel op de laadmethode moeten lijken. Het loopt door alle Te doen
zonde geddy.todos
om de te vinden ID kaart
waar we naar op zoek zijn. Vervolgens wordt dat item uit de array gesplitst en wordt de callback aangeroepen. Als het de array niet vindt, roept het de callback met een fout aan.
Laten we dit nu in onze controller gebruiken.
Open uw controller opnieuw en voer de verwijderen
actie. Het zou er ongeveer zo uit moeten zien:
this.remove = function (req, resp, params) this.respond (params: params); ;
Bewerk het om het er zo uit te zien:
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 .naam); );
We passeren de ID kaart
die we kregen van de params in de vorm post in de verwijderen
methode die we zojuist hebben gemaakt. Als we een foutmelding krijgen, gaan we terug naar de Bewerk
actie (we nemen aan dat het formulier de verkeerde info heeft geplaatst). Als we geen foutmelding hebben ontvangen, stuur het verzoek dan gewoon naar de inhoudsopgave
actie.
Dat is het! Werden gedaan.
U kunt de verwijderfunctie testen door uw server opnieuw te starten en een nieuwe te maken Te doen
item, klik op de link en klik vervolgens op de knop "Verwijderen". Als je het goed hebt gedaan, zou je terug moeten zijn op de indexpagina met dat item verwijderd.
In de volgende tutorial gebruiken we de ontzagwekkende mongodb-wrapper-module van http: //i.tv om ons te behouden Te doen
zit in MongoDB. Met Geddy zal dit gemakkelijk zijn; alles wat we moeten veranderen is de model-adapter.
Als u vragen heeft, kunt u hier een opmerking achterlaten of een probleem met github openen.