Updating QuizEditComponent

The QuizEditComponent features a very simple yet perfectly working form, hence it's perfect to become our guinea pig.

Open the quiz-edit.component.ts file and update it in the following way (new lines are highlighted):

import { Component, Inject, OnInit } from "@angular/core";
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

[...]

export class QuizEditComponent {
title: string;
quiz: Quiz;
form: FormGroup;

[...]

constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private http: HttpClient,
private fb: FormBuilder,
@Inject('BASE_URL') private baseUrl: string) {

// create an empty object from the Quiz interface
this.quiz = <Quiz>{};

// initialize the form
this.createForm();

var id = +this.activatedRoute.snapshot.params["id"];
if (id) {
this.editMode = true;

// fetch the quiz from the server
var url = this.baseUrl + "api/quiz/" + id;
this.http.get<Quiz>(url).subscribe(result => {
this.quiz = result;
this.title = "Edit - " + this.quiz.Title;

// update the form with the quiz value
this.updateForm();

[...]

Here's a summary of what we did here:

  • We added a reference to the @angular/form components we'll use within the class
  • We added the form: FormGroup class property that will host our Form Model
  • We injected the fb: FormBuilder object that will be used to create and update the Form Model
  • We added two calls to a couple of new internal methods--createForm() and updateForm()--which will respectively initialize and update the Form Model

Now we need to add these two new methods; scroll down until you reach the onSubmit() method and put these code lines right before it:

createForm() {
this.form = this.fb.group({
Title: ['', Validators.required],
Description: '',
Text: ''
});
}

updateForm() {
this.form.setValue({
Title: this.quiz.Title,
Description: this.quiz.Description || '',
Text: this.quiz.Text || ''
});
}

These two methods are quite self-explanatory; they both use the FormBuilder instance to respectively initialize the Form Model and set its values using the Data Model. As we can see by looking at the updated constructor source code, the createForm() method is called before the Data Model is retrieved from the web server, while updateForm() is executed as soon as the HttpClient gets the job done.

We're not done yet; we also need to perform some minor, yet very important changes to the onSubmit() method itself. Here's the updated code (new/updated lines are highlighted):

[...]

onSubmit() {

// build a temporary quiz object from form values
var tempQuiz = <Quiz>{};
tempQuiz.Title = this.form.value.Title;
tempQuiz.Description = this.form.value.Description;
tempQuiz.Text = this.form.value.Text;

var url = this.baseUrl + "api/quiz";

if (this.editMode) {

// don't forget to set the tempQuiz Id,
// otherwise the EDIT would fail!
tempQuiz.Id = this.quiz.Id;

this.http
.post<Quiz>(url, tempQuiz)
.subscribe(res => {
this.quiz = res;
console.log("Quiz " + this.quiz.Id + " has been
updated.");
this.router.navigate(["home"]);
}, error => console.log(error));
}
else {
this.http
.put<Quiz>(url, tempQuiz)
.subscribe(res => {
var v = res;
console.log("Quiz " + v.Id + " has been created.");
this.router.navigate(["home"]);
}, error => console.log(error));
}
}


[...]

The source code comments should help understand what we just did. However, let's quickly review the changes we made:

  • We removed the quiz parameter from the onSubmit() method signature, as we won't need it anymore; in Model-Driven Forms, we need to work with the Form Model, leaving the Data Model immutable.
  • We created a tempQuiz local instance, filling it with the values retrieved by the Form Model. It's worth noting that we also had to set its Id in case of this.editMode, otherwise the PUT request would fail, being the Id field obviously required for edits; we retrieved it directly from the Data Model, since we never put it in the Form Model, as we don't need it there.
  • We passed the new tempQuiz instance as the new source parameter for our PUT and POST HTTP request calls.

We're done with the class file. Now we need to change the quiz-edit.component.html template file as well (new/updated lines are highlighted):

<div class="quiz-edit">
<h2>{{title}}</h2>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="title">Quiz title:</label>
<br />
<input type="text" id="title"
formControlName="Title" required
placeholder="choose a title..."
class="form-control" />
</div>
<div class="form-group">
<label for="description">Quiz description:</label>
<br />
<input type="text" id="description"
formControlName="Description"
placeholder="enter a description..."
class="form-control" />
</div>
<div class="form-group">
<label for="text">Quiz informative text:</label>
<br />
<textarea id="text"
formControlName="Text"
placeholder="enter a text..."
class="form-control"></textarea>
</div>
<div class="form-group commands">
<button *ngIf="editMode" type="submit"
[disabled]="form.invalid"
class="btn btn-success">
Apply Changes
</button>
<button *ngIf="!editMode" type="submit"
[disabled]="form.invalid"
class="btn btn-success">
Create the Quiz!
</button>
<button *ngIf="!editMode" type="submit"
(click)="onBack()"
class="btn btn-default">
Cancel
</button>
</div>
</form>

<question-list *ngIf="editMode" [quiz]="quiz"></question-list>

<result-list *ngIf="editMode" [quiz]="quiz"></result-list>

</div>

We wrapped our DIVs within a <form> element and used the [formGroup] and formControlName template attributes to connect the form and its input fields to the Form Model. We also made some important modification to our buttons, removing (click)="onSubmit(quiz)"--which is called by the form itself without the attribute--and adding [disabled]="form.invalid" to prevent the user from performing a submit when the form has an invalid state.

That's it, we just upgraded our previous Template-Driven form into a brand-new Model-Driven form; now that we took the first steps into the Reactive path, we can add some validators to further improve its usability, consistency, and robustness.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.184.102