

In dit tweede deel van deze blogpostserie zal ik mijn ervaringen delen over het maken van een notitie-app. We behandelen het maken, bijwerken en verwijderen van notities en het toevoegen van authenticatie. Deel één van deze blogpostserie vind je hier, waarin we onze Firebase database en Vue-applicatie hebben opgezet om notities weer te geven.
Wat zijn we aan het maken?

Voortbouwend op ons vorige werk, zullen we onze notities app afmaken.
Afhankelijk van je vaardigheidsniveau, zullen de volgende stappen je ongeveer 20 tot 45 minuten kosten om te voltooien.
Stap 1: Notities toevoegen
In onze vorige blogpost hebben we al leesnotities gemaakt, maar daarvoor moesten we ze handmatig toevoegen in onze Firestore-database. Laten we nu de functionaliteit creëren waarmee we rechtstreeks via de interface van onze applicatie notities kunnen toevoegen. In Notes.vue:
<template> <div class="notes"><h1> Notities <el-button type="primary" size="medium" @click="addDialogVisible = true"><i class="el-icon-circle-plus"></i> Notitie toevoegen</el-button> </h1> <el-table :data="tableData" empty-text="Bezig met laden, of geen records te tonen." border> <el-table-column type="expand"><template slot-scope="props"><p></p></template> </el-table-column> <el-table-column label="Note title"> <template slot-scope="props"></template> </el-table-column> <el-table-column label="Datum toegevoegd/gewijzigd"prop="date"></el-table-column> <el-table-column fixed="right"label="width="90">
<template slot-scope="scope"><el-button type="info" size="small" icon="el-icon-edit" circle></el-button> <el-button type="danger" size="small" icon="el-icon-delete" circle style="margin-left: 5px;"></el-button> </template> </el-table-column> </el-table> <el-dialog title="Notitie toevoegen" :visible.sync="addDialogVisible"width="30%"><el-form ref="addNoteRuleForm" :model="addNoteRuleForm" :rules="rules"><el-form-item label="Note title" prop="title"><el-input type="text" placeholder="Note title" v-model="addNoteRuleForm.title"></el-input> </el-form-item> <el-form-item label="Note content" prop="content"><el-input type="textarea" placeholder="Note content" v-model="addNoteRuleForm.content"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"><el-button @click="addDialogVisible = false">Cancel</el-button> <el-button type="primary" @click="addNoteForm('addNoteRuleForm'); addDialogVisible = false;">Bevestig</el-button> </span> </el-dialog> </div> </template> <script> import { db } from '@/main' export default {naam: 'Notities', data() { return { tableData: [], addDialogVisible: false, addNoteRuleForm: {titel: '', inhoud: ''}, regels: { title: [ { required: true, message: "Note title can't be empty", trigger: 'blur' }] , content: [ { required: true, message: "Notitie-inhoud mag niet leeg zijn", trigger: 'blur' } }, created () { db.collection('notities').get().then(querySnapshot => { querySnapshot.forEach(doc => { const data = {' id': doc.id,' date': doc.data().date,' title': doc.data().title,' content': doc.data().content }this.tableData.push(data) }), methods: { addNoteForm (formName) {var self = this; this.$refs[formName].validate((valid) => { if (valid) {console.log('Form valid'); } } } anders {console.log('error submit!!')}} </script>CSS CSS-beheerprogramma's.
De bovenstaande code laat zien dat we een@click="addDialogVisible = true" handler hebben toegevoegd aan onze knop 'Notitie toevoegen' en deze hebben geregistreerd in onze 'data'-haak zodat deze standaard false is.
We hebben ook het dialoogvenster zelf toegevoegd dat wordt weergegeven op basis van deze 'addDialogVisible'-waarde. In dit dialoogvenster hebben we een ElementUI-formulier toegevoegd met titel- en inhoudsvelden die enkele validatieregels hebben, ook gespecificeerd in onze 'data hook'.
Als we nu op de knop drukken om de notitie toe te voegen, geven we de refs van onze formname door, die een Vue-object retourneert met de velden die moeten worden gevalideerd.
Vervolgens voegen we onze database query toe. Wijzig de methode 'addNoteForm' als volgt:
addNoteForm (formName) {var self = this; this.$refs[formName].validate((valid) => { if (valid) {var today = new Date().toLocaleString('en-GB'); db.collection('notes').add({' title': this.addNoteRuleForm.title, 'content': this.addNoteRuleForm.content, 'date': today }).then(function (docRef) { self.$message( {type: 'succes', message: 'Notitie succesvol toegevoegd' });}).catch(function (error) {console.error('Fout bij toevoegen document: ', error) }) } else {console.log('fout bij verzenden!!') })
Nadat je dit hebt getest door een geldig formulier in te dienen, zie je de succesmelding. Maar er is nog steeds een probleem met het tonen van de nieuw toegevoegde notitie in onze tabel. Door de pagina te verversen, wordt hij wel getoond.
De reden hiervoor is dat we de database-aanroep om de notities op te halen hebben uitgevoerd via de 'created' haak. Dit zal één keer gebeuren als we de pagina openen, maar niet nadat we onze database hebben bijgewerkt. Laten we dat wat flexibeler maken door de get query naar een methode te verplaatsen:
created () {this.getNotes()}, methods: { getNotes () { db.collection('notes').orderBy('date').get().then(querySnapshot => {this.tableData = []; querySnapshot.forEach(doc => { const data = {' id': doc.id,' date': doc.data().date,' title': doc.data().title,' content': doc.data().content }this.tableData.push(data);})}, addNoteForm (formName) {var self = this; this.$refs[formName].validate((valid) => { if (valid) {var today = new Date().toLocaleString('en-GB'); db.collection('notes').add({' title': this.addNoteRuleForm.title, 'content': this.addNoteRuleForm.content, 'date': today }).then(function (docRef) {self.getNotes(); self.$message( {type: 'succes', message: 'Notitie succesvol toegevoegd' });}).catch(function (error) {console.error('Fout bij toevoegen document: ', error) }) } anders {console.log('error submit!!') } }
Als je goed kijkt, heb ik ook een orderBy('date') toegevoegd aan de query. Als we nu nog een noot toevoegen, wordt onze tabel foutloos bijgewerkt en wordt de laatste noot toegevoegd aan de onderste rij. Als je dit andersom wilt, verander dan orderBy('date') in orderBy('date', 'desc').
Stap 2: Notities verwijderen
Het verwijderen van een item is vrij eenvoudig, maar moet vanuit het oogpunt van gebruikerservaring ook niet te eenvoudig zijn. Daarom heb ik besloten om het verwijderen af te handelen na een bevestigingsvenster van ElementUI.
Voeg eerst een @click handler toe aan het verwijder icoon waar we de ID van de notitie die we willen verwijderen naartoe sturen:
<template slot-scope="props"><el-button type="info" size="small" icon="el-icon-edit" circle></el-button> <el-button type="danger" size="small" icon="el-icon-delete" circle style="margin-left: 5px;" @click="deleteNote(props.row.id)"></el-button> </template>
Merk op dat ik ook de slot-scope="scope" heb veranderd in slot-scope="props" in de template tag om overeen te komen met de rest van de props die worden doorgegeven aan de tabel.
Laten we nu de deleteNote methode registreren:
deleteNote (noteId) {var self = this; this.$confirm('Hiermee wordt de notitie permanent verwijderd. Doorgaan?", "Waarschuwing", { confirmButtonText: 'OK', cancelButtonText: 'Annuleren', type: 'waarschuwing'}).then() => { db.collection('notes').doc(noteId).delete().then(function() {self.getNotes(); self.$message( {type: 'succes', message: 'Verwijderen voltooid'}); }).catch(function(error) {console.error("Fout bij verwijderen notitie: ", error);}); }).catch() => {console.log("Verwijderen geannuleerd"); });CSS.
En voilà! Het verwijderen van notities is nu volledig afgedekt.
Stap 3: Notities bewerken
Voeg net als bij het verwijderen een bewerkingshandler toe aan de bewerkingsknop, samen met een 'editDialogVisible'-waarde zoals we die hebben toegevoegd voor de 'addDialog'.
<template slot-scope="props"><el-button type="info" size="small" icon="el-icon-edit" circle @click="editNote(props.row.id); editDialogVisible = true"></el-button> <el-button type="danger" size="small" icon="el-icon-delete" circle style="margin-left: 5px;" @click="deleteNote(props.row.id)"></el-button> </template>
Vervolgens moeten we ook het dialoogvenster maken waarin de bewerking plaatsvindt:
<el-dialog title="Notitie bewerken": visible.sync="editDialogVisible"width="30%"><el-form ref="editNoteRuleForm" :model="editNoteRuleForm" :rules="rules"><el-form-item label="Notitie titel" prop="title"><el-input type="text" placeholder="Notitie titel" v-model="editNoteRuleForm.title" value="editNoteRuleForm.title"></el-input> </el-form-item> <el-form-item label="Note content" prop="content"><el-input type="textarea" placeholder="Note content" v-model="editNoteRuleForm.content" value="editNoteRuleForm.content"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"><el-button @click="editDialogVisible = false">Cancel</el-button> <el-button type="primary" @click="saveEditedNote('editNoteRuleForm', editNoteRuleForm); editDialogVisible = false;">Bevestig</el-button> </span> </el-dialog>
Onze data hook (we hebben editDialogVisible en editNoteRuleForm toegevoegd) moet dan worden bijgewerkt tot:
data() { return { tableData: [], addDialogVisible: false, addNoteRuleForm: { title: '', content: ''}, editDialogVisible: false, editNoteRuleForm: { id: '', title: '', content: ''}, regels: { title: [ { required: true, message: "Note title can't be empty", trigger: 'blur' }] , content: [ { required: true, message: "Opmerking inhoud kan niet leeg zijn", trigger: 'blur' } }
Daarnaast moeten we ook een editNote methode toevoegen die de gegevens ophaalt op basis van de notitie ID en de waarde van de editDialog velden invult:
editNote (noteId) {var self = this;this.editNoteRuleForm.title = '';this.editNoteRuleForm.content = ''; db.collection('notes').doc(noteId).get().then(function(doc) { if (doc.exists) {self.editNoteRuleForm.id = doc.id;self.editNoteRuleForm.title = doc.data().title;self.editNoteRuleForm.content = doc.data().content; } else {console.log("No such document!"); }).catch(function(error) {console.log("Error getting document:", error);}); }
Tot zover is het ophalen van de notitie in ons bewerkingsvenster behandeld, maar we hebben nog steeds de methode saveEditedNote nodig:
saveEditedNote (note, noteObj) {var self = this;var today = new Date().toLocaleString('en-GB'); this.$refs[note].validate((valid) => { if (valid) { db.collection('notes').doc(noteObj.id).set({ 'title': noteObj.title, 'content': noteObj.content, 'date': today }).then(function() {self.getNotes(); self.$message( {type: 'succes', message: 'Notitie succesvol bewerkt' });}) .catch(function(error) {console.error("Fout bij het schrijven van document: ", error); });}) }
Hier stellen we onze database record in op de nieuwe waarde gespecificeerd door onze gevalideerde formuliervelden, een bijgewerkte datum wordt ook doorgegeven. Bij succes wordt er een 'Note successfully edited' bericht getoond.
Dat was het! Onze missie om een basis CRUD-applicatie te maken op basis van VueJS en Firebase is een feit!

Bonusstap: Authenticatie
Iemand vroeg me naar de authenticatiefunctionaliteit in onze vorige blogpost, dus ik zal het hebben over het maken van een basisauthenticatie voor onze app, gebaseerd op de authenticatie-API die Firebase biedt.
Ga naar je Firebase console en navigeer naar de link 'Authenticatie' in de zijbalk onder 'Ontwikkelen'. Schakel nu de eenvoudige Email/Paswoord Authenticatie in.

Nu kunnen we beginnen met het bouwen van de login- en registratiepagina's. Dat zijn in principe gewoon formulieren zoals we eerder hebben gedaan. Het enige verschil hier is dat we de methodesfirebase.auth().createUserWithEmailAndPassword enfirebase.auth().signInWithEmailAndPassword gebruiken.
Inloggen.vue:
<template> <div class="login"> <el-container> <el-main> <el-row :gutter="20"> <el-col :span="12"> <h1>Login bij uw account</h1> <el-form ref="form" :model="form"> <el-form-item label="E-mailadres"> <el-input type="email" placeholder="E-mail" v-model="form.email"></el-input> </el-form-item> <el-form-item label="Password"> <el-input type="password" placeholder="Password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" v-on:click="login">Login</el-button> </el-form-item> <el-form-item> Geen account? <router-link to="/signup">Maak er een aan</router-link> </el-form-item> </el-form> </el-col> </el-row> </el-main> </el-container> </div> </template> <script> import firebase from 'firebase' export default {naam: 'login', data: functie () {retour {formulier: { email: '', wachtwoord: '' } }, methoden: { login: functie () { firebase.auth().signInWithEmailAndPassword(this.form.email, this.form.password).then( (gebruiker) => { this.$router.replace('/home') this.$notify({ title: 'Geweldig!', message: 'Je bent nu ingelogd.', type: 'succes' })}, (err) => { this.$message.error( {boodschap: 'Oeps. ' + err.message } ) } }</script>
Aanmelden.vue:
<template> <div class="sign-up"> <el-container> <el-main> <el-row :gutter="20"> <el-col :span="12"> <h1>Aanmelden voor een FireNotes account</h1> <el-form ref="form" :model="form"> <el-form-item label="E-mailadres"> <el-input type="email" placeholder="E-mail" v-model="form.email"></el-input> </el-form-item> <el-form-item label="Password"> <el-input type="password" placeholder="Password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" v-on:click="signUp">Aanmelden</el-button> </el-form-item> <el-form-item> Heeft u al een account? <router-link to="/login">Login</router-link> </el-form-item> </el-form> </el-col> </el-row> </el-main> </el-container> </div> </template> <script> import firebase from 'firebase' export default {naam: 'SignUp', data: function () { return { form: { email: '', wachtwoord: '' } }, methods: { signUp: functie () { firebase.auth().createUserWithEmailAndPassword(this.form.email, this.form.password).then( (user) => { this.$router.replace('/home') this.$notify({ title: 'Geweldig!', message: 'Uw account is aangemaakt.', type: 'succes' })}, (err) => { this.$message.error( {boodschap: 'Oeps. ' + err.message } ) } }</script>
We kunnen deze weergaven nog steeds niet zien omdat we onze routes nog moeten bijwerken. Ga naar main.js en vervang deze door het volgende (vergeet je API-sleutel en Project ID niet):
import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) import firebase from 'firebase' import 'firebase/firestore' firebase.initializeApp({ apiKey: 'yourApiKey', projectId: 'yourProjectId'}) export const db = firebase.firestore() const settings = { timestampsInSnapshots: true }db.settings(settings) import VueRouter from 'vue-router' Vue.use(VueRouter) import App from '@/App' import HelloWorld from '@/components/HelloWorld' import Notes from '@/components/Notes' import Login from '@/components/Login' import SignUp from '@/components/SignUp' const routes = [ { path: '*', redirect: '/login'}, { path: '/', redirect: '/login'}, { path: '/login', name: 'Login', component: Login }, { path: '/signup', name: 'SignUp', component: SignUp }, { pad: '/home', naam: 'HelloWorld', component: HelloWorld, meta: { requiresAuth: true }}, { path: '/notes', name: 'Notes', component: Notes, meta: { requiresAuth: true }} const router = nieuwe VueRouter({routes}) router.beforeEach((to, from, next) => {const currentUser = firebase.auth().currentUser const requireAuth = to.matched.some(record => record.meta.requiresAuth)if (requiresAuth && !currentUser) next('/login')else if (!requiresAuth && currentUser) next('/home')else next()})/* eslint-disable no-new */firebase.auth().onAuthStateChanged(function (user) { new Vue({ el: '#app', router: router, render: h => h(App), components: { App }})})
Hier hebben we een aantal routes toegevoegd voor inloggen en aanmelden, en meta: { requiresAuth: true; } toegevoegd aan de pagina's waarop we beperkte toegang willen. We controleren met Firebase of de gebruiker is geauthenticeerd in de functie router.beforeEach, voordat we hem registreren in onze app. Als de auth-status verandert, wordt de controle opnieuw uitgevoerd.
Nu werkt het dus vrij goed, maar we willen de navigatie in de zijbalk verbergen als de gebruiker niet is ingelogd, dus we hebben de aangemaakte haak en de v-if op <el-aside> toegevoegd. We hebben ook een uitloglink toegevoegd aan de navigatie. Ons App.vue bestand ziet er nu zo uit:
<template> <div id="app"> <el-container> <el-header> <img class="logo" src="./assets/logo.png" /> </el-header> <el-container> <el-aside width="300px" v-if="user"> <el-menu default-active="home" :router="true" class="el-menu-vertical-demo"> <el-menu-item index="home"> <i class="el-icon-menu"></i> <span>Home</span> </el-menu-item> <el-menu-item index="notes"> <i class="el-icon-document"></i> <span>Notes</span> </el-menu-item> <el-menu-item index="/logout" v-on:click="logout"> <i class="el-icon-setting"></i> <span>Logout</span> </el-menu-item> </el-menu> </el-aside> <el-main> <router-view/> </el-main> </el-container> </el-container> </div> </template> <script> import firebase from 'firebase' export default {naam: 'App', created () {this.user = firebase.auth().currentUser || false;}, methods: { uitloggen: functie () { firebase.auth().signOut().then() => {this.$router.replace('/login')}) }</script> <style> html, body { margin: 0; } body { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grijswaarden; color: #2c3e50; }. el-header { border-bottom: 1px solid #e6e6e6; display: flex; align-items: center; width: 100%; }. el-header button { float: right; }. el-menu-item { border-bottom: 1px solid #e6e6e6; }. logo { max-width: 50%; max-height: 50%; margin-right: auto; }</style>
En daar hebben we het, een toepassing voor notities op één pagina waar je een account kunt aanmaken, kunt inloggen en notities kunt maken, lezen, bijwerken en verwijderen.
Voel je vrij om deze code / kennis aan te passen of op voort te bouwen om je eigen VueJS / Firebase projecten te maken. Laat me weten hoe je het hebt gedaan!
Vragen, opmerkingen?
Krijg je het niet aan de praat? Heb je meer uitleg nodig over bepaalde stukjes code? We zijn een en al oor. Laat het ons weten en we nemen zo snel mogelijk contact met je op.
What others have also read


Bij de ontwikkeling van software kunnen aannames ernstige gevolgen hebben en we moeten altijd op onze hoede zijn. In deze blogpost bespreken we hoe je omgaat met aannames bij het ontwikkelen van software. Stel je voor... je rijdt naar een bepaalde pl
Lees verder

ACA doet veel projecten. In het laatste kwartaal van 2017 deden we een vrij klein project voor een klant in de financiële sector. De deadline voor het project was eind november en onze klant werd eind september ongerust. We hadden er echter alle vert
Lees verder

OutSystems: een katalysator voor bedrijfsinnovatie In het snelle zakelijke landschap van vandaag de dag moeten organisaties innovatieve oplossingen omarmen om voorop te blijven lopen. Er zijn veel strategische technologische trends die cruciale bedri
Lees verderWant to dive deeper into this topic?
Get in touch with our experts today. They are happy to help!

Want to dive deeper into this topic?
Get in touch with our experts today. They are happy to help!

Want to dive deeper into this topic?
Get in touch with our experts today. They are happy to help!

Want to dive deeper into this topic?
Get in touch with our experts today. They are happy to help!


