­čôő Kapitel 5: Ein Formular zum Adoptieren hinzuf├╝gen

Ziel Implementiere ein Formular, um einen Hund zu adoptieren
Was du lernen wirst Formulare in einer Vue-App erstellen und validieren
Was du daf├╝r ben├Âtigst Einen modernen Browser, z.B. Google Chrome. Ein Account bei CodeSandbox.io. Falls du nicht mehr wei├čt, wo du warst, kannst du die Basis f├╝r dieses Kapitel von hier importieren. Wie das geht, steht im Anhang 1
Dauer 1 Stunde

Anleitung

Falls du das Projekt von vorn beginnen musst, klone dieses Projekt in Code Sandbox, nachdem du dich eingeloggt hast. Daf├╝r klickst du auf den Link Import form Github unten links auf der Hauptseite und f├╝gst die URL des Repositories in das Feld. Du kannst ebenfalls mit dem Projekt fortfahren, dass du in Kapitel 4 erstellt hast.

In diesem Kapitel implementieren wir ein Formular, das man ausf├╝llen kann nachdem man Hunde auf die Favoriten-Liste gesetzt hat. Zuerst m├╝ssen wir eine neue Komponente erstellen, die dieses Formular beinhaltet, und eine neue Route f├╝r dieses Formular im Router konfigurieren.

Ger├╝st f├╝r die Formular-Komponente

Erstelle eine neue Datei Form.vue im views-Ordner.

Schreibe den <template></template> in die neue Datei. F├╝ge ein div-Tag hinzu und schreibe dort hinein den Text This form works!. So sollte die Komponente jetzt aussehen:

Copy
<template>
	<div>
		This form works!
	</div>
</template>
1
2
3
4
5

Jetzt kommt die Route f├╝r diese neue Komponente. Importiere die Form-Komponente in main.js:

Copy
import Form from './views/Form';
1

F├╝ge eine neue Option in der routes-Liste hinzu:

Copy
{ path: "/form", component: Form }
1

├ťberpr├╝fen wir mal, wie das funktioniert. Rufe die /form-Route auf, indem du /form and die Shop-URL anh├Ąngst. Du solltest den Text 'This form works!' zwischen dem Header und Footer sehen.

F├╝gen wir eine Klasse an das div, um es etwas zu gestalten.

Copy
<div class="form-wrapper">
	This form works!
</div>
1
2
3

F├╝ge einen <style scoped></style> Block unter den <template> Block ein. In diesem Tag werden wir ein paar Styles f├╝r unsere Formular-Komponente definieren. Zuerst ein Padding (=innerer Rand) f├╝r form-wrapper:

Copy
<style scoped>
	.form-wrapper {
		padding: 40px;
	}
</style>
1
2
3
4
5

Das Formular bauen

Jetzt ist es an der Zeit das eigentliche Formular zu bauen. Wir werden daf├╝r die Vuetify-Komponente v-form nutzen.

­čĺí

Mehr ├╝ber Vuetify-styled Formulare kannst du in der Dokumentation nachlesen.

Als erstes f├╝gen wir eine leere v-form in den form-wrapper ein:

Copy
<template>
	<div class="form-wrapper">
		<v-form> </v-form>
	</div>
</template>
1
2
3
4
5

So wird nat├╝rlich noch nichts angezeigt. Dazu m├╝ssen wir Formularfelder hinzuf├╝gen.

F├╝r die Formularfelder nutzen wir die Vuetify-Komponente namens v-text-field. Diese hat ein Attribut label, mit dem wir ein Label (=Beschreibung/Namen) f├╝r das Feld definieren k├Ânnen. Wir erstellen Felder mit den Namen "Name", "Email" und "Phone" in v-form:

Copy
<div class="form-wrapper">
	<v-form>
		<v-text-field label="Name"></v-text-field>
		<v-text-field label="Email"></v-text-field>
		<v-text-field label="Phone"></v-text-field>
	</v-form>
</div>
1
2
3
4
5
6
7

Sieht schon besser aus!

Einen Absenden-Button hinzuf├╝gen

Irgendwie muss das Formular abgeschickt werden. Daf├╝r f├╝gen wir einen Absenden (=submit) Button unter die Formularfelder ein:

Copy
<div class="form-wrapper">
	<v-form>
		<v-text-field label="Name"></v-text-field>
		<v-text-field label="Email"></v-text-field>
		<v-text-field label="Phone"></v-text-field>
		<v-btn>Submit</v-btn>
	</v-form>
</div>
1
2
3
4
5
6
7
8

Unser Button ist erstmal links ausgerichtet. Um ihn zu zentrieren, schreiben wir text-align: center in die form-wrapper Styles:

Copy
.form-wrapper {
	padding: 40px;
	text-align: center;
}
1
2
3
4

Der Submit-Button macht erstmal noch nichts. Wir werden eine Methode hinzuf├╝gen, die alle Werte der Formularfelder in der Konsole ausgibt. Daf├╝r m├╝ssen wir eine Property f├╝r jedes Feld in den Komponenten-data schreiben und diese mit den Feldern ├╝ber die v-model-Direktive verkn├╝pfen.

­čĺí

Die v-model-Direktive erzeugt eine bi-direktionale Verkn├╝pfung zwischen Formular- und Textfeld-Elemente. Sie w├Ąhlt automatisch den richtigen Weg basierend auf dem Feldtyp, um den Wert zu aktualisieren.

Daten-Verkn├╝pfung

­čĺí

Was bedeutet bi-direktionale Verkn├╝pfung? Das bedeutet, dass wir das data-Attribut entweder direkt ├╝ber die verkn├╝pfte Komponente oder innerhalb der Komponente selbst ver├Ąndern k├Ânnen und der neue Wert wird automatisch an beiden Stellen aktualisiert.

F├╝gen wir einen <script></script>-Block ├╝ber die Styles ein, f├╝ge das export dfault ein und implementiere die data-Komponente (data sollte eine Funktion sein, die ein Objekt liefert):

Copy
<script>
	export default {
	  data() {
	    return {

	    }
	  }
	}
</script>
1
2
3
4
5
6
7
8
9

Jetzt f├╝gen wir die neuen Properties dem Objekt hinzu:

Copy
data() {
	return {
	    name: "",
	    email: "",
	    phone: ""
	};
	}
1
2
3
4
5
6
7

Wie du siehst, sind alles zun├Ąchst leere Texte (=string).

Verkn├╝pfe diese Properties mit den entsprechenden Formularfeldern im Template indem du die v-model-Direktive hinzuf├╝gst:

Copy
<v-form>
	<v-text-field label="Name" v-model="name"></v-text-field>
	<v-text-field label="Email" v-model="email"></v-text-field>
	<v-text-field label="Phone" v-model="phone"></v-text-field>
	<v-btn>Submit</v-btn>
</v-form>
1
2
3
4
5
6

├ändere jetzt den Wert der name-Property in data anstelle des leeren Textes (z.B. zu deinem eigenen Namen). Das Formularfeld hat sich ver├Ąndert! Wenn du etwas in das Textfeld schreibst, wird die verkn├╝pfte data-Property ebenfalls aktualisiert. So funktioniert bi-direktionale Verkn├╝pfung.

Jetzt k├Ânnen wir die Eingaben aus dem Formular in der Konsole ausgeben, wenn das Formular abgeschickt wird. Daf├╝r implementieren wir eine Methode (erstelle die methods direkt nach der data-Funktion, vergiss nicht das Komma nach der schlie├čenden Klammer von data):

Copy
methods: {
  submit() {
    console.log(
      "Name:",
      this.name,
      "Email:",
      this.email,
      "Phone:",
      this.phone
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

and verkn├╝pfe es mit dem Klick auf den Submit-Button:

Copy
<v-btn @click="submit">Submit</v-btn>
1

F├╝lle das Formula mit Testdaten aus und klicke auf Submit. Du kannst sehen, dass die Daten aus dem Formular in der Code Sandbox Konsole ausgegeben werden.

Die abgeschickten Informationen anzeigen

Ausgaben in der Konsole sind schon ganz gut, aber so sollte das nicht in der fertigen App funktionieren. Anstatt die Werte in der Konsole auszugeben, zeigen wir sie anstelle des Formulars an. Zuerst brauchen wir nat├╝rlich einen Indikator, der ├╝berpr├╝ft, ob das Formular bereits abgeschickt wurde.

Daf├╝r erstellen wir eine neue Property in data names submitted und setzen diese initial auf false (wenn die Komponente erstellt wird, sollte das Formular noch nicht abgeschickt sein):

Copy
data() {
  return {
    name: "",
    email: "",
    phone: "",
    submitted: false
  };
},
1
2
3
4
5
6
7
8

Jetzt m├╝ssen wir submitted auf true setzen, wenn das Formular abgeschickt wird. Diese Logik f├╝gen wir in die submit-Methode ein anstelle der console.log-Befehle:

Copy
methods: {
  submit() {
    this.submitted = true;
  }
}
1
2
3
4
5

Jetzt m├╝ssen wir noch ein div erstellen, das das Formular ersetzt. Kopiere diesen Code ├╝ber das <v-form>-Tag:

Copy
<div class="text-xs-center">
	<h2>Thank you for you interest, we will contact you soon</h2>
	<div class="details text-xs-left">
		<h3 class="blue-grey--text">Customer details</h3>
		<p><strong>Name:</strong> {{name}}</p>
		<p><strong>Email:</strong> {{email}}</p>
		<p><strong>Phone:</strong> {{phone}}</p>
	</div>
	<v-btn to="/">Go to homepage</v-btn>
</div>
1
2
3
4
5
6
7
8
9
10

und f├╝ge daf├╝r ein paar Styles ein in den <style>-Tag:

Copy
.details {
	padding-top: 30px;
}
h3 {
	padding-bottom: 20px;
}
1
2
3
4
5
6

Daten von einer Bedingung abh├Ąngig anzeigen

Jetzt sehen wir sowohl das div mit unseren Informationen aus dem Formular als auch das Formular selbst. Das sieht komisch aus.

Wir wollen sie abh├Ąngig von einer Bedingung anzeigen lassen. Wir werden das div anzeigen, wenn submitted true ist; ansonsten wird das Formular angezeigt.

Also f├╝gen wor ein v-if="submitted" dem div und ein v-else dem Formular v-form hinzu:

Copy
<div class="text-xs-center" v-if="submitted">
	...
</div>
<v-form v-else>
	...
</v-form>
1
2
3
4
5
6

Jetzt wird das Formular nach dem Abschicken versteckt und die zuvor eingegebenen Informationen werden angezeigt.

Validierung hinzuf├╝gen

Jetzt fehlt noch eine richtige Validierung f├╝r das Formular. Zun├Ąchst bauen wir aber erstmal einen Button ein, der zum Formular f├╝hrt. ├ľffne die Favorites.vue und kopiere folgenden Code nach dem schlie├čenden </v-list-item>-Tag.

Copy
<v-btn to="/form">Adopt</v-btn>
1

Super! Jetzt k├Ânnen wir ganz einfach zum Formular navigieren. Die Validierung fehlt trotzdem noch. Im Moment k├Ânnen wir einfach irgendetwas in das E-Mail-Feld eintragen oder Buchstaben als Telefonnummer abschicken. Wir k├Ânnen sogar ein leeres Formular abschicken!

Um das zu ├Ąndern, m├╝ssen wir erstmal eine neue data-Property namens valid hinzuf├╝gen und diese mit der v-model-Direktive mit der v-formverkn├╝pfen. Bearbeite in Form.vue das data-Objekt:

Copy
data() {
	return {
	    name: "",
	    email: "",
	    phone: "",
	    submitted: false,
	    valid: true
	};
},
1
2
3
4
5
6
7
8
9

Verkn├╝pfe das Formular mit der neuen valid-Property:

Copy
<v-form v-else v-model="valid"></v-form>
1

Wir deaktivieren den Abschicken-Button, solange die eingegebenen Informationen nicht valide sind:

Copy
<v-btn @click="submit" :disabled="!valid">Submit</v-btn>
1

Jetzt k├Ânnen wir Validierungsregeln schreiben.

­čĺí

Alle Eingabefelder in der v-form haben eine rules-Property, die eine Liste von Funktionen entgegen nimmt. Sobald sich der Eingabewert eines Feldes ├Ąndert, erhalten alle Funktionen in dieser Liste den neuen Wert. Die Validierung schl├Ągt fehlt, sobald eine dieser Funktionen false oder einen String zur├╝ck liefert. Vuetify wird diese Ergebnisse daf├╝r benutzen, um das v-model auf true oder false zu setzen. Indem wir also das Attrribut v-model="valid" in unserem Tag v-form, werden wir wissen, ob data in unserem Formular valide ist oder nicht. Wir werden diese Information benutzen, um den Submit Button zu deaktivieren, falls notwendig. Aktuell w├Ąre unser Button niemals deaktiviert, da wir noch keine Regeln geschrieben haben, um das v-model zu validieren - daher ist die Form immer valide.

Validierung 1: Name

Zuerst wollen wir ein leeres name-Feld verbieten. Dazu schreiben wir eine nameRules-Eigenschaft in unsere data:

Copy
data() {
  return {
    name: "",
    email: "",
    phone: "",
    submitted: false,
    valid: true,
    nameRules: []
  };
},
1
2
3
4
5
6
7
8
9
10

Jetzt kommt die erste Regel. Denk dran, Validierungsregeln sind Funktionen, die den Wert des Feldes erhalten und einen Bool'schen Wert zur├╝ck geben; true bedeutet, dass das Feld einen korrekten/validen Wert beinhaltet, false bedeutet, dass der Wert nicht korrekt ist. Also sieht die erste Regel so aus:

Copy
nameRules: [(name) => !!name];
1

Was passiert hier? !name gibt true zur├╝ck, wenn der Name leer ist und andernfalls false. Mit der zweiten Verneinung kehren wir das noch einmal um. Die doppelte Verneinung wird oft genutzt, um zu ├╝berpr├╝fen, ob ein String nicht-leer ist.

F├╝ge nameRules zu der rules-Property des name-Feldes hinzu und markiere das Feld zus├Ątzlich als required (=Pflichfeld):

Copy
<v-text-field label="Name" required :rules="nameRules" v-model="name"></v-text-field>
1

Klicke jetzt in das Name-Feld und dann in ein anderes. Du sieht, wie Name rot wird und darunter der Text false erscheint. (Der Submit-Button ist immer noch deaktiviert.)

Fehlermeldungen k├Ânnen mit Hilfe des ||-Operators in der Regel erg├Ąnzt werden. Der Wert der Validierung ist also false OR <Fehlermeldung>. Lass uns die Fehlermeldung f├╝r das Name-Feld verbessern:

Copy
nameRules: [(name) => !!name || 'Name is required'];
1

Jetzt sieht die Fehlermeldung doch schon besser aus!

Wir f├╝gen eine weitere Regel hinzu: Ein Name darf nicht k├╝rzer als zwei Buchstaben sein:

Copy
nameRules: [
	(name) => !!name || 'Name is required',
	(name) => name.length > 2 || 'Name must be longer than 2 characters',
];
1
2
3
4

Schreibe nur einen Buchstaben in das Name-Feld, die neue Fehlermeldung sollte angezeigt werden.

Validierung 2: Email

Jetzt wechseln wir zum E-Mail-Feld. Zuerst erstellen wir die emailRules-Property in data und f├╝gen den nicht-leeren Check wie zuvor auch beim Namen hinzu:

Copy
emailRules: [(email) => !!email || 'Email is required'];
1

Vergiss nicht required und die rules-Property an das E-Mail-Feld zu schreiben:

Copy
<v-text-field label="Email" required :rules="emailRules" v-model="email"></v-text-field>
1

Die zweite Regel f├╝r das E-Mail-Feld ist etwas komplizierter. Wir wollen ├╝berpr├╝fen, ob die eingegebene E-Mail einem bestimmten Muster entspricht, diese Muster hei├čen Regul├Ąre Ausdr├╝cke (=regular expressions / RegEx).

­čĺí

Regul├Ąre Ausdr├╝cke sind Muster, die Strings auf bestimmte Buchstaben/Zahlen-Kombinationen ├╝berpr├╝fen. In JavaScript sind Regul├Ąre Ausdr├╝cke auch Objekte.

Mehr Informationen zu RegEx kannst du in diesem MDN Artikel nachlesen.

F├╝ge den Regul├Ąren Ausdruck zu den Validierungsregeln hinzu:

Copy
emailRules: [
	(email) => !!email || 'Email is required',
	(email) => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(email) || 'Email must be valid',
];
1
2
3
4

Gebe jetzt irgendwelche zuf├Ąlligen Zeichen im E-Mail-Feld ein. Du siehst die Fehlermeldung; eine E-Mail muss ein @-Zeichen, einen Punkt und mindestens zwei Zeichen nach dem Punkt haben. Wenn du versuchst, deine eigene E-Mail-Adrresse einzuf├╝gen, wirst du sehen, dass ein Fehler angezeigt wird.

Validierung 3: Telefon

Jetzt wechseln wir zum phone-Feld. Wir erstellen ein ├Ąhnliches Regelset wie f├╝r name. Die Telefonnummer sollte mindestens sieben Zeichen lang sein:

Copy
phoneRules: [
	(phone) => !!phone || 'Phone is required',
	(phone) => phone.length >= 7 || 'Phone number should be at least 7 digits',
];
1
2
3
4

Aber man kann immer noch Buchstaben eingeben. Und die Telefonnummer wird nicht formatiert. Um das zu erreichen, werden wir die vue-the-mask hinzuf├╝gen. Daf├╝r klicke in Code Sandbox auf den Reiter Explorer -> Dependencies -> Add Dependency und suche nach vue-the-mask. Wenn du es installiert hast, wirst du sehen, dass es zu deiner package.json hinzugef├╝gt wurde. Nun wurde vue-the-mask installiert, wir m├╝ssen es nun noch der Komponente als Direkte hinzuf├╝gen.

Als erstes, f├╝gst du vue-the-mask in deiner Form.vue hinzu:

Copy
import { mask } from 'vue-the-mask';
1

Im Anschluss, f├╝gst du die Direktive direkt vor data in deinem <script> Block hinzu:

Copy
directives: {
  mask,
},
1
2
3

­čĺí

Indem das Objekt directives unserer Komponent mit einem Element mask hinzugef├╝gt wurde, registieren wir mask in dieser Komponente. Das bedeutet, dass wir von nun an, in dieser Komponent, v-mask bei jedem beliebigen Element verwenden k├Ânnen. Alle Direktiven in Vue besetzen das K├╝rrzel v- am Anfang, Daher wird aus der Direktive mask dann automatisch v-mask. Mehr Information findest du hier.

Nachdem wir nun v-mask als Direktive zur Verf├╝gung stehen haben, k├Ânnen wirr folgendes in unser Tag v-text-field hinzuf├╝gen:

Copy
v-mask="'(###) ### - ####'"
1

Indem wir '(###) ### - ####' als Input f├╝r die Maske benutzen, limitieren wir die M├Âglichkeiten der Eingabe zu Ziffern in diesem spezifischen Format. Das bedeutet, dass es m├Âglich ist Nummern wir (555) 555-1234 einzugeben, nicht aber Ziffern in einem anderen Format oder Charaktere, die keine Ziffern sind. Sollte dein Land ein anderes Format benutzen, ├Ąndere es nun gerne ab.

Im Ganzen sollte das Tag nun folgenderma├čen aussehen:

Copy
<v-text-field label="Phone" required :rules="phoneRules" v-mask="'(###) ### - ####'" v-model="phone"></v-text-field>
1

Jetzt kannst du nur Zahlen eingeben und die Telefonnummer wird direkt formatiert.

L├Âsche alle Favoriten beim Absenden des Formulars

Als letztes m├Âchten wir noch die Favoritenliste wieder leeren, wenn wir das Formular absenden. Gehe dazu in store/store.js und kopiere den folgenden Code in das mutations-Objekt:

Copy
clearFavorites(state) {
  state.favorites = [];
}
1
2
3

F├╝ge die Aktion zum Aufrufen der neuen Mutation zu actions hinzu:

Copy
clearFavorites({ commit }) {
  commit("clearFavorites");
}
1
2
3

Gehe zur├╝ck in die Form.vue-Datei und rufe die neue Aktion in der submit-Methode auf:

Copy
submit() {
  this.$store.dispatch("clearFavorites");
  this.submitted = true;
}
1
2
3
4

Jetzt wird die Favoritenliste geleert, nachdem das Formular abgesendet wird.

­čÄŐHerzlichen Gl├╝ckwunsch, du hast das Projekt abgeschlossen!­čÄŐ

Ergebnis

chapter 5 final