QuestionListComponent

The first thing we'll do is to implement a QuestionListComponent that will show a list of questions for any given quiz; once done, we'll add it to our already-existing QuizEditComponent, thus enabling our users to view, create, edit, and/or delete them from the same place where they can edit the details of the parent quiz.

Start with creating the /ClientApp/app/components/question/ folder, then right-click on it and add the question-list.component.ts file with the following content (relevant lines are highlighted):

import { Component, Inject, Input, OnChanges, SimpleChanges } from "@angular/core";
import { Router } from "@angular/router";
import { HttpClient } from "@angular/common/http";

@Component({
selector: "question-list",
templateUrl: './question-list.component.html',
styleUrls: ['./question-list.component.css']
})

export class QuestionListComponent implements OnChanges {
@Input() quiz: Quiz;
questions: Question[];
title: string;

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

this.questions = [];
}

ngOnChanges(changes: SimpleChanges) {
if (typeof changes['quiz'] !== "undefined") {

// retrieve the quiz variable change info
var change = changes['quiz'];

// only perform the task if the value has been changed
if (!change.isFirstChange()) {
// execute the Http request and retrieve the result
this.loadData();
}
}
}

loadData() {
var url = this.baseUrl + "api/question/All/" + this.quiz.Id;
this.http.get<Question[]>(url).subscribe(res => {
this.questions = res;
}, error => console.error(error));
}

onCreate() {
this.router.navigate(["/question/create", this.quiz.Id]);
}

onEdit(question: Question) {
this.router.navigate(["/question/edit", question.Id]);
}

onDelete(question: Question) {
if (confirm("Do you really want to delete this question?")) {
var url = this.baseUrl + "api/question/" + question.Id;
this.http
.delete(url)
.subscribe(res => {
console.log("Question " + question.Id + " has been
deleted.");

// refresh the question list
this.loadData();
}, error => console.log(error));
}
}
}

Once done, follow up with the question-list.component.html template file:

<h3>Questions</h3>
<div *ngIf="questions.length > 0">
<table class="questions">
<thead>
<tr>
<th>Text</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let question of questions">
<td>{{question.Text}}</td>
<td><input type="button" value="Edit"
(click)="onEdit(question)" />
<input type="button" value="Delete"
(click)="onDelete(question)" /></td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="questions.length == 0">
This quiz has no questions (yet):
click the <strong>Add a new Question</strong> button to add the first one!
</div>
<input type="button" value="Add a new Question" (click)="onCreate()" />

Also, follow up with the question.list.component.css style sheet file:

table.questions {
min-width: 500px;
}

We've got lot of new stuff here; let's see how it works.

By looking at the class implementation, we can see how we're expecting to receive a quiz property, which will most likely come from the parent component--the quiz-edit.component.ts file. Since it will come from there, we had to use the @Input() decorator to authorize the binding. The quiz property will be used within the loadData() method to assemble the URL for the server-side API to retrieve all the existing questions for the current quiz; as usual, that request will be issued by the Angular HttpClient, just like we did a number of times earlier.

However, it's difficult to miss that we're taking a different approach here. The news is the loadData() method itself, which is not called in the constructor phase, nor in the ngOnInit() life cycle hook we used in the past; we can clearly see that it's executed within the ngOnChanges() method, which is something we have never heard of.

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

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