CRUD – Luo, lue, päivitä, poista – tietokantatoimintojen neljä pyhää Graalin maljaa. Ne ovat ainoat asiat, joita tulet koskaan tarvitsemaan tehdessäsi mitään merkittävää tietokannallasi. Toki voit lisätä kyselyiden monimutkaisuutta, mutta loppujen lopuksi kaikki tiivistyy näihin neljään toimintoon.
Firebase on Googlen omistama pilvipohjainen järjestelmä, joka sisältää API-koukut, tiedostojen tallennustilan, auth-järjestelmän ja hosting-ominaisuudet. Se on paljon aliarvostettu järjestelmä, jota pitäisi hyödyntää enemmän prototyyppien luomiseen ja nopeaan sovelluskehitykseen.
Jos haluat käynnistää progressiivisen web-sovelluksen, mutta sinulla ei ole backend-kokemusta palvelimien perustamisesta, API-rajapintojen luomisesta ja tietokantojen kanssa tekemisissä olemisesta, Firebase on loistava vaihtoehto etupään kehittäjille, jotka saattavat tuntea itsensä eristäytyneiksi ja jumiutuneiksi valtavaan tietomäkeen, joka heidän on käsiteltävä saadakseen sovelluksensa edes käyntiin.
Tai jos sinulla on vain vähän aikaa, Firebase voi lyhentää kehitystyöaikasi lähes puoleen, jotta voit keskittyä käyttäjäkokemukseen ja näiden UI-virtojen toteuttamiseen. Se on myös tarpeeksi joustava, jotta voit tarvittaessa siirtää front end -sovelluksesi pois ja käyttää eri tietokantaa.
Tässä on pikaopas CRUD-toimintojen toteuttamiseen Angularin ja Firebasen avulla.
Tässä on pelkistetty kahvitilaussovellus, jossa voit lisätä tilauksia (create), listata tilauksia tietokannasta (read), merkitä tilauksen suoritetuksi (update) ja poistaa tilauksen (delete).
Tämän tutoriaalin tarkoituksena on auttaa sinua pääsemään alkuun Firebase Firestoren kanssa ja näkemään, kuinka helppoa Googlen omistamaan palveluun on muodostaa yhteys ja päästä alkuun. Tämä ei ole mainos Googlelle (en saa heiltä mitään palkkiota tästä), vaan ainoastaan havainnollistaa, miten Angular pelaa tietokannan kanssa.
Sovellus, jonka aiomme tehdä, ei ole täydellinen. Siitä puuttuu asioita kuten tietojen validointi ja miljoona mahdollista ominaisuutta, joita voin myös lisätä. Mutta siitä ei ole kyse. Pointti on perustaa Angularissa mahdollisimman nopeasti ja saada se toimimaan live-tietokannan kanssa.
Nyt riittää esittely – tässä on koodin läpikäynti.
Alkuasetukset
Asetetaan Angular-sovellus Angular CLI:n kautta. Jos sinulla ei vielä ole Angular CLI:tä, voit lukea siitä lisää täältä.
Lyhyesti sanottuna, suorita yksinkertaisesti nämä komennot terminaalissasi hakemistossa, jossa haluat Angular-sovelluksesi olevan. Tässä ovat komennot ja mitä ne tekevät.
npm install -g @angular/cli
Asenntaa Angular CLI:n päätelaitteeseesi, jos sinulla ei vielä ole sitä.
ng new name-of-app-here
Luo uuden Angular-projektin käyttäen uusinta saatavilla olevaa Angular-versiota.
cd name-of-app-here
Kun luot uuden projektin Angular CLI:n avulla, se luo sinulle uuden projektikansion. cd
vie sinut terminaalin kautta tuohon kansioon.
ng serve
Tämä on käynnistää ja ajaa Angular-projektisi.
Angularin asettaminen
Luomme tähän Angular-sovellukseen yhteensä 3 uutta osaa – tilaukset, tilausluettelo ja shared/ordersService. Kaksi ensimmäistä ovat komponentteja, jotka sisältävät sovelluksen käyttöliittymän ja shared/orders service, joka pitää kaikki Firebase API-kutsut yhdessä.
Luoaksesi tarvittavat tiedostot, suorita seuraavat komennot:
ng g c orders
g
tarkoittaa generate ja c
tarkoittaa component. Komennon viimeinen osa on tiedostosi nimi, joka yllä olevassa tapauksessa on nimeltään orders. Voit myös käyttää komentoa ng generate component orders
saavuttaaksesi saman vaikutuksen.
Luo toinen komponentti tilauslistalle seuraavalla komennolla.
ng g c order-list
Ja lopuksi käytä palvelussa s
komentoa c
:n sijasta c
kuten alla:
ng g s shared/orders
Tämä luo tiedoston orders.service.ts
kansioon nimeltä shared. Muista lisätä orders.service.ts
tiedostoon app.module.ts
, koska tätä ei tehdä puolestasi automaattisesti kuten komponentit. Voit tehdä tämän import
:n kautta ja lisäämällä sen providers
-luetteloon näin:
import { OrdersService } from "./shared/orders.service";
...
providers:
...
CSS
Tässä opetusohjelmassa käytämme Materialize CSS:ää saadaksemme lopullisen sovelluksemme näyttämään paremmalta kuin oletus-css. Se ei ole välttämätöntä, ja voit käyttää mitä tahansa CSS-kehystä tai omaa mukautettua CSS:ääsi, jos haluat. Voit tutustua Materialize CSS:n yksityiskohtiin täällä.
Käytämme myös Googlen materiaalikuvakkeita painikkeina, joilla voimme merkitä kahvitilauksen valmiiksi tai poistaa tilauksen.
Yksi tapa toteuttaa tämä on, että alla oleva koodi on aivan </head>
-tagin yläpuolella index.html
-tiedostossasi, joka sijaitsee src
-kansiossa.
<!-- Compiled and minified Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified Materialize JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script><!-- Google Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
Alustava Angular-näkymän koodi
Kohdasta app.component.html
poista kaikki aloituskoodi. Käytämme tässä omaa sisältöämme.
Koukutamme juuri luomamme komponentin ja näytämme ne ruudulla käyttämällä valitsimia app-orders
ja app-order-list
. Tätä varten kirjoitamme alla olevan koodin:
<div class="container">
<div class="row">
<app-orders class="col s6"></app-orders>
<app-order-list class="col s6"></app-order-list>
</div>
</div>
Luokat container
, row
, col
ja s6
ovat osa Materialize CSS-ristikkojärjestelmää. Kaikki luokat, jotka tulet näkemään tämän opetusohjelman loppuosassa, ovat Materialize CSS:stä, ellei toisin mainita.
Lomakkeen asettaminen
Lomakkeiden asettamista varten tuo ReactiveFormsModule
app.module.ts
:ssä ja muista tuoda se imports
-joukkoon.
import { ReactiveFormsModule } from "@angular/forms";
Tuo orders.service.ts
:n sisälle @angular/forms
:sta FormControl
ja FormGroup
ja luo uusi lomake constructor
:n ulkopuolelle, jossa voit asettaa lomakkeen ominaisuudet seuraavasti:
import { FormControl, FormGroup } from "@angular/forms";
...
...export class OrdersService {
constructor() {}
form = new FormGroup({
customerName: new FormControl(''),
orderNumber: new FormControl(''),
coffeeOrder: new FormControl(''),
completed: new FormControl(false)
})
}
Käytämme näitä arvoja Firebaseen tallentamiseen hiukan myöhemmässä vaiheessa tätä opetusohjelmaa.
Lomakkeen käyttäminen komponentin sisällä
import
OrdersService
-luokan sisällyttäminen komponenttiisi, jotta voit käyttää objektia komponenttisi sisällä ja luoda sitten luokan objektin constructor
sisälle.
import { OrdersService } from "../shared/orders.service";
...
constructor(private ordersService:OrdersService){}
Komponenttisi orders.component.html
sisällä käytä formGroup
-direktiiviä viitataksesi lomakkeen objektiin, joka on luotu OrdersService
. Jokainen formControlName
viittaa OrdersService
-luokan sisälle luodussa formGroup
:ssä käyttämiimme nimiin. Näin siihen liittyvä ohjain voi käyttää lomakkeeseen kirjoitettuja muuttujia. Katso koodi alla:
<form ="this.ordersService.form">
<input placeholder="Order Number"
formControlName="orderNumber"
type="text"
class="input-field col s12">
<input placeholder="Customer Name"
formControlName="customerName"
type="text"
class="input-field col s12">
</form>
orders.component.ts
:ssä perustamme array off kahvia varten looping through meidän orders.component.html
:ssä. Teoriassa voisit myös asettaa tämän Firestore-tietokantaasi, tehdä kutsun kokoelmaan ja käyttää sitä sitten. Mutta pituuden vuoksi asetamme sen paikallisena joukkona. Määritä OrdersComponent
-luokkasi sisällä seuraava array:
coffees = ;
Seuraava joukko
coffees = ;
Käy läpi orders.component.html
– ja <form>
-tunnisteiden sisällä käyttäen *ngFor
-toimintakäsittelijää (click)
lisätäksesi uusia kahveja tilaukseesi. Näytämme tilausluettelon aivan alapuolella mahdollisuudella poistaa yksittäinen kahvi seuraavasti:
<button class="waves-effect waves-light btn col s4"
*ngFor="let coffee of coffees"
(click)="addCoffee(coffee)">
{{coffee}}
</button><ul class="collection">
<li *ngFor="let coffee of coffeeOrder">
<span class="col s11"> {{ coffee }} </span>
<a class="col s1" (click)="removeCoffee(coffee)">x</a>
</li>
</ul>
Luot orders.component
:n sisälle tyhjän array:n, johon sijoitat kahvitilauksen, käytät toimintoa addCoffee()
lisätäksesi uusia kahveja ja removeCoffee()
poistaaksesi juoman tilausluettelosta.
coffeeOrder = ;addCoffee = coffee => this.coffeeOrder.push(coffee);removeCoffee = coffee => {
let index = this.coffeeOrder.indexOf(coffee);
if (index > -1) this.coffeeOrder.splice(index, 1);
};
Lomakkeen lähettämisen käsittely
Lisää Submit Order -syötteen <form>
-tagien sisälle ja alareunaan ja lisää onSubmit()
klikkauksen käsittelijään alla olevan kaltaisesti:
<form ="this.ordersService.form" (ngSubmit)="onSubmit()"> ...
<button
class="waves-effect waves-light btn col s12"
(click)="onSubmit()">
Submit
</button>
</form>
Luo orders.component
:n sisälle tyhjä onSubmit
funktio välivaihetta varten. Lisäämme siihen pian tapahtumankäsittelyn. Tässä vaiheessa lomakkeesi pitäisi olla valmis Firebase-tietokantaan kytkemistä varten.
Listauskomponentin asettaminen
Nyt tarvitsemme vain tilan, jossa voimme näyttää kahvitilauksemme tietokannasta. Toistaiseksi asetamme vain telineen html:n.
Navigoi kohtaan order-list.component.html
ja luo taulukko, jossa on 3 otsikkoa ja 5 datasolua. Kolmeen ensimmäiseen datasoluun tallennetaan tietokannasta vedetyt arvot ja kahteen viimeiseen tallennetaan lisätoiminnot, joiden avulla voit merkitä tilauksen valmiiksi tai poistaa tilauksen.
Firebasen perustaminen
Mene Firebase-konsoliin ja lisää uusi projekti.
Lisää projektin nimi, hyväksy ehdot ja napsauta kohtaa ’Luo projekti’.
Kun Firebase-projektisi on luotu, näet jotakin tällaista.
Luo tietokanta valitsemalla sivupaneelissa (Develop-kohdan alla) Database (tietokanta) ja napsauttamalla sitten Cloud Firestore -bannerin alla olevaa Create Database (Luo tietokanta) -painiketta.
Valitse tietoturvasääntöjä varten aloita testitilassa. Voit muokata sitä myöhemmin.
Saat tyhjän Firestore-tietokannan näin.
Firebase Firestoren liittäminen Angulariin
Voidaksesi liittää Angular-sovelluksesi Firebaseen sinun on asennettava firebase
ja @angular/fire
paketit. Näin saat käyttöösi AngularFireModule
ja AngularFirestoreModule
. Asenna ne terminaalissa seuraavalla komennolla.
npm i --save firebase @angular/fire
Kytkentöjen toteuttaminen
Palaa takaisin Firebase-verkkokonsoliin ja nappaa konfigurointitiedot Angular-sovelluksessasi käytettäväksi. Nämä löytyvät Project Overviewsivultasi. Se näyttää jotakuinkin tältä:
Kopioi korostettu osa koodista, siirry environment.ts
-tiedostoosi (joka sijaitsee environments
-kansion sisällä) ja liitä konfiguraation tiedot environment
-objektin sisälle firebaseConfig
. Katso alla oleva esimerkki:
export const environment = {
production: false,
firebaseConfig: {
apiKey: "xxx",
authDomain: "xxxx.firebaseapp.com",
databaseURL: "https://xxxx.firebaseio.com",
projectId: "xxxx",
storageBucket: "xxxx.appspot.com",
messagingSenderId: "xxxxx"
}
};
Importoi aiemmin asentamasi paketit ja environment.ts
-tiedosto app.module.ts
:iin.Sinun täytyy alustaa AngularFireModule
sillä firebaseConfig
:llä, jonka asetukset olet juuri tehnyt. Katso esimerkki alla:
import { environment } from "src/environments/environment";
import { AngularFireModule } from "@angular/fire";
import { AngularFirestoreModule } from "@angular/fire/firestore";
...
@NgModule({
...
imports:
...
})
Firestoren perustaminen palveluun
Importoi AngularFirestore
tiedostoon orders.service.ts
ja ilmoita se konstruktorissa, jotta palvelusi tietää siitä.
...
import { AngularFirestore } from '@angular/fire/firestore';
...
export class OrdersService {
constructor( private firestore: AngularFirestore ) {}
...
}
Nyt olet valmis aloittamaan tämän Angular + Firebase Firestore -oppaan CRUD-osuuden.
C is for Create
Luodaksesi uuden tietueen upouuteen Firestore-tietokantaasi sinun täytyy kutsua .add()
. Teemme tämän orders.service.ts
-tiedoston sisällä.
Tehdäksesi tämän sinun on määritettävä collection
-nimi ja mitä tietoja haluat työntää tietokantaan. Meidän tapauksessamme se on coffeeOrders
.
Alla oleva esimerkkikoodi käyttää lupausta palauttaakseen Firebase-kutsun ja antaa sinun päättää, mitä haluat tehdä sen jälkeen, kun kaikki on tehty.
...
createCoffeeOrder(data) {
return new Promise<any>((resolve, reject) =>{
this.firestore
.collection("coffeeOrders")
.add(data)
.then(res => {}, err => reject(err));
});
}
...
Kutsuaksesi tätä funktiota komponentissasi siirry kohtaan orders.component.ts
ja tee onSubmit()
-funktion ja toimintokäsittelijän sisällä kutsu createCoffeeOrder()
kautta ordersService
.
Alhaalla oleva esimerkki tekee jonkin verran tietojen käsittelyä kuvaamalla coffeeOrder
-matriisin lomakkeen arvoksi coffeeOrder
. Olen myös luonut data
-muuttujan rakenneuudistuksen vuoksi (yhdessä sen kanssa, että createCoffeeOrder()
:een ei tarvitse syöttää massiivisen pitkää nimeä).
...
onSubmit() {
this.ordersService.form.value.coffeeOrder = this.coffeeOrder;
let data = this.ordersService.form.value;
this.ordersService.createCoffeeOrder(data)
.then(res => {
/*do something here....
maybe clear the form or give a success message*/
});
}
...
Ja viola! Olet nyt luonut tietueen localhost Angular-sovelluksestasi Firestore-tietokantaan.
R is for Read
Voidaksesi näyttää kahvitilaustietosi, tarvitset lukufunktion orders.service.ts
:ssäsi. Seuraava koodiesimerkki antaa sinulle kaikki coffeeOrders
-kokoelmaasi tallennetut arvot.
...
getCoffeeOrders() {
return
this.firestore.collection("coffeeOrders").snapshotChanges();
}
...
Käyttääksesi tätä funktiota sinun on kutsuttava sitä orders-list.component.ts
:stä . Voit tehdä tämän tuomalla OrdersService
tiedostoon ja alustamalla sen constructor
:ssä.
...
import { OrdersService } from "../shared/orders.service";
...export class OrderListComponent implements OnInit {
constructor(private ordersService:OrdersService){}
...
}
Luo funktio, joka sisältää kutsusi ja alustat sen ngOnInit()
:ssä kutsuaksesi sitä, kun näkymä ladataan ensimmäisen kerran. Luo coffeeOrders
-muuttuja kuvaamaan tietokannastasi subscribe()
kautta palautettuja tuloksia. Käytämme tätä iterointiin ja näyttämiseen order-list.component.html
...
ngOnInit() {this.getCoffeeOrders();}
... coffeeOrders; getCoffeeOrders = () =>
this.ordersService
.getCoffeeOrders()
.subscribe(res =>(this.coffeeOrders = res));...
Käyttääksesi coffeeOrders
:tä or
der-list.component.html
:ssäsi, käytä *ngFor
:tä kierrättääksesi palautettua arraya. Sinun täytyy myös tehdä hieman inceptionia ja tehdä toinen silmukka coffeeOrder
-osalle, jotta saat luettelon kahveista jokaiselle asiakkaalle. On olemassa tehokkaampiakin tapoja tehdä tämä, mutta tätä opetusohjelmaa varten katso alla olevaa esimerkkikoodia:
...
<tbody>
<tr *ngFor="let order of coffeeOrders">
<td>{{ order.payload.doc.data().orderNumber }}</td>
<td>{{ order.payload.doc.data().customerName }}</td>
<td><span
*ngFor="let coffee of order.payload.doc.data().coffeeOrder">
{{ coffee }}
</span>
</td>
</tr>
</tbody>
...
Ja siinä se on. Olet nyt kytkenyt lukutoiminnot Angular-sovellukseesi.
U is for Update
Esitettäköön, että haluamme pystyä merkitsemään kahvitilauksen valmiiksi tietokannassa ja tehdä jotain rivikohdalle muutoksen perusteella. Koska snapshot()
pitää kirjaa kaikista tapahtuvista muutoksista, sinun ei tarvitse tehdä mitään seurantaa tai kyselyä tietokantaan.
Luomme taulukkoon toisen datasolun, jossa on Google Materialize Iconsin ”check”-kuvake ja kytkemme sen (click)
-tapahtumaan, joka kutsuu funktiota markCompleted()
toiminnossasi order-list.component.ts
. Siirrämme myös tietyn järjestyksen tätä silmukkaa varten.
Asetamme -attribuutin
completed
-arvolla tietosoluun, jotta se voi dynaamisesti määrittää, haluammeko ’check’-kuvakkeen näkyviin. Olemme alun perin asettaneet tämän arvon false
, kun loimme lomakkeen ensimmäisen kerran orders.service.ts
.
...
<td ="order.payload.doc.data().completed"
(click)="markCompleted(order)">
<i class="material-icons">check</i>
</td>
...
Inside order-list.component.ts
, luo funktio markCompleted()
, joka käyttää injektoitua data
:a välittääkseen sen funktiolle nimeltä updateCoffeeOrder()
orders.service.ts
.
...
markCompleted = data =>
this.ordersService.updateCoffeeOrder(data);
...
Inside orders.service.ts
luo käsittelyfunktio. Tämä funktio muodostaa yhteyden ja kutsuu Firestore-tietokantaa valitun kokoelman ja asiakirjan id:n perusteella. Tiedämme jo, että kokoelmamme on nimeltään coffeeOrders
ja voimme löytää asiakirjan id:n komponenttifunktion kutsusta välitettyjen parametrien perusteella.
.set()
asettaa tietyn tietueen mihin tahansa välittämilläsi tiedoilla. .set()
ottaa vastaan kaksi parametria – tietosi ja asetusobjektin. Jos käytät merge: true
, se tarkoittaa, että päivität vain välitetyn arvo-avain-parin sen sijaan, että korvaisit koko dokumentin sillä, mitä välitit.
...
updateCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.set({ completed: true }, { merge: true });
}
...
Nyt kun napsautat näkymässäsi ’tarkista’-kuvaketta, se päivittää tietokantasi ja katoaa, koska -attribuuttisi on nyt asetettu
true
:ksi.
D is for Delete
Viimeistä toimintoa varten asetamme kaiken samalla tavalla kuin päivitysprosessin – mutta sen sijaan, että päivitämme tietueen, poistamme sen.
Asetetaan toinen datasolu, jossa on klikkaustapahtuman käsittelijä, joka kutsuu deleteOrder()
-funktiota. Siirrämme silmukassa order
-datan instanssin, kun ’delete_forever’-kuvaketta napsautetaan. Tarvitset tätä asiakirjan id:tä varten. Katso esimerkki alla olevasta koodista:
...
<td ="order.payload.doc.data().completed"
(click)="deleteOrder(order)">
<i class="material-icons">delete_forever</i>
</td>
...
Luo order-list.component.ts
-tiedoston sisälle siihen liittyvä funktio, joka kutsuu deleteCoffeeOrder()
-funktiota orders.service.ts
-tiedoston sisälle.
...
deleteOrder = data => this.ordersService.deleteCoffeeOrder(data);
...
Luo orders.service.ts
-tiedoston sisälle deleteCoffeeOrder()
-funktio ja käytä injektoitua data
:a selvittääksesi, mikä on dokumentin id. Kuten päivitys, sinun on tiedettävä sekä kokoelman nimi että asiakirjan id, jotta voit tunnistaa oikein, minkä tietueen haluat poistaa. Käytä .delete()
kertoaksesi Firestorelle, että haluat poistaa tietueen.
...
deleteCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.delete();
}
...
Nyt kun napsautat ’delete_forever’ -kuvaketta, Angular-sovelluksesi laukeaa ja käskee Firestorea poistamaan tietyn tietueen. Tietueesi katoaa näkymästä, kun määritetty asiakirja poistetaan.
Loppusovellus
Täältä löydät koko työprojektin Github-arkiston. Sinun täytyy luoda oma Firebase-tietokantasi ja kytkeä se itse päivittämällä konfigurointitiedostot. Koodi itsessään ei ole täydellistä, mutta olen pitänyt sen hyvin minimaalisena, jotta näet, miten Firestore toimii Angular-sovelluksessa ilman, että sinun tarvitsee käydä läpi koodiviidakkoa.
Olen yrittänyt tiivistää opetusohjelmaa niin paljon kuin mahdollista ilman, että siitä puuttuu mitään yksityiskohtia. Se oli kova sekoitus, mutta kuten yllä näkyy, suuri osa siitä on enimmäkseen Angular-koodia eikä juurikaan Firestorea. Firebase Firestore voi tehdä paljon monimutkaisempia kyselyjä, mutta esittelyn vuoksi olen pitänyt sen yksinkertaisena. Teoriassa, jos tietorakenteesi pysyy samana, voit vaihtaa Firestoren pois ja laittaa eri joukon API-yhteyksiä minimaalisella refaktoroinnilla.
Loppusanat
Pidän Firebasea henkilökohtaisesti sen takia, että sillä on helppo luoda nopeasti tuotantokelpoisia projekteja ilman, että tarvitsee luoda kokonainen backend ja palvelin sen tueksi. Kustannuksiltaan se ei ole liian paha ja testiprojektit ovat ilmaisia käynnistää (ja he eivät pakota sinua syöttämään luottokorttitietojasi ennen kuin olet valmis vaihtamaan pakettia). Kaiken kaikkiaan lomakkeen ja sovellusta ympäröivän käyttöliittymän luominen vei enemmän aikaa kuin sovelluksen liittäminen Firestoreen. En ole lisännyt lomakkeen validointia tähän opetusohjelmaan pituuden vuoksi, mutta aion luoda siitä toisen postauksen tulevaisuudessa.