สารบัญเนื้อหา
- สร้าง Member Edit Component และ Route
- สร้าง Template สำหรับการแก้ไข Profile
- ใช้งาน CanDeactivate Route Guard
- สร้าง API สำหรับการอัพเดตข้อมูล Profile
- อัพเดตข้อมูล Profile
1. สร้าง Member Edit Component และ Route
สร้าง member-edit Component ภายใต้ members
import MemberEditComponent ใน app.module.ts
เพิ่ม Route ใน routes.ts
{ path: 'member/edit', component: MemberEditComponent },
กำหนด link ใน nav.component.html
<a href="#" class="dropdown-item" [routerLink]="['/member/edit']"><i class="fa fa-user"></i> Edit Profile</a>
สร้าง member-edit.resolver.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router';
import { User } from '../_models/user';
import { UserService } from '../_services/user.service';
import { AlertifyService } from '../_services/alertify.service';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AuthService } from '../_services/auth.service';
@Injectable()
export class MemberEditResolver implements Resolve<User> {
constructor(private userService: UserService, private router: Router,
private authService: AuthService, private alertify: AlertifyService) {}
resolve(route: ActivatedRouteSnapshot): Observable<User> {
return this.userService.getUser(this.authService.decodeToken.nameid).pipe(
catchError(error => {
this.alertify.error('Problem retrieving your data');
this.router.navigate(['/members']);
return of(null);
})
);
}
}
เพิ่ม MemberEditResolver ใน app.module.ts
เพิ่ม resolve: (user: MemberEditResolver) ใน routes.ts
เพิ่มการเรียกใช้งาน จาก member-edit.component.ts
import { Component, OnInit } from '@angular/core';
import { User } from 'src/app/_models/user';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-member-edit',
templateUrl: './member-edit.component.html',
styleUrls: ['./member-edit.component.css']
})
export class MemberEditComponent implements OnInit {
user: User;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.data.subscribe(data => {
this.user = data.user;
});
}
}
เพิ่มการแสดงผลชื่อของสมาชิกใน member-edit.component.html
<p>
{{user.knownAs}}
</p>
ทดสอบรันและคลิกที่เมนู Edit Profile
2. สร้าง Template สำหรับการแก้ไข Profile
สร้าง template ใน member-edit.component.html
<div class="container mt-4">
<div class="row">
<div class="col-sm-4">
<h1>Your Profile</h1>
</div>
<div class="col-sm-8">
<div *ngIf="editForm.dirty" class="alert alert-info">
<strong>Information: </strong>You have made change. Any unsaved change will be lost!
</div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<div class="card">
<img src="{{user.photoUrl}}" alt="{{user.knownAs}}" class="card-img-top img-thumbnail">
<div class="card-body">
<div>
<strong>Location:</strong>
<p>{{user.city}}, {{user?.country}}</p>
</div>
<div>
<strong>Age:</strong>
<p>{{user.age}}</p>
</div>
<div>
<strong>Last Active:</strong>
<p>{{user.lastActive}}</p>
</div>
<div>
<strong>Member since:</strong>
<p>{{user.created}}</p>
</div>
</div>
<div class="card-footer">
<div class="btn-group d-flex">
<button [disabled]="!editForm.dirty" form="editForm" class="btn btn-success btn-block">Save Change</button>
</div>
</div>
</div>
</div>
<div class="col-sm-8">
<div class="tab-panel">
<tabset class="member-tabset">
<tab heading="Edit Profile">
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateUser()">
<h4>Description</h4>
<textarea name="introduction" rows="6" class="form-control" [(ngModel)]="user.introduction"></textarea>
<h4>Looking for</h4>
<textarea name="lookingFor" rows="6" class="form-control" [(ngModel)]="user.lookingFor"></textarea>
<h4>Interests</h4>
<textarea name="interests" rows="6" class="form-control" [(ngModel)]="user.interests"></textarea>
<h4>Location Details</h4>
<div class="form-inline">
<label for="city">City</label>
<input type="text" name="city" [(ngModel)]="user.city" class="form-control">
<label for="country">Country</label>
<input type="text" name="country" [(ngModel)]="user.country" class="form-control">
</div>
</form>
</tab>
<tab heading="Edit Photos">
<p>Edit photo will go here</p>
</tab>
</tabset>
</div>
</div>
</div>
</div>
member-edit.component.css
.img-thumbnail {
margin: 25px;
width: 85%;
height: 85%;
}
.card-body {
padding: 0 25px;
}
.card-footer {
padding: 10px 15px;
background-color: #fff;
border-top: none;
}
member-edit.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { User } from 'src/app/_models/user';
import { ActivatedRoute } from '@angular/router';
import { AlertifyService } from 'src/app/_services/alertify.service';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-member-edit',
templateUrl: './member-edit.component.html',
styleUrls: ['./member-edit.component.css']
})
export class MemberEditComponent implements OnInit {
@ViewChild('editForm') editForm: NgForm;
user: User;
constructor(private route: ActivatedRoute, private alertify: AlertifyService) { }
ngOnInit() {
this.route.data.subscribe(data => {
this.user = data.user;
});
}
updateUser() {
console.log(this.user);
this.alertify.success('Profile updated successfully');
this.editForm.reset(this.user);
}
}
ทดสอบรัน
3. ใช้งาน CanDeactivate Route Guard
ใช้ CanDeactivate เพื่อป้องกันการเปลี่ยนหน้า หรือปิดไปโดยที่ยังไม่ได้กดบันทึกข้อมูล
สร้าง prevent-unsaved-changes.guard.ts
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { MemberEditComponent } from '../members/member-edit/member-edit.component';
@Injectable()
export class PreventUnsavedChanges implements CanDeactivate<MemberEditComponent> {
canDeactivate(component: MemberEditComponent) {
if (component.editForm.dirty) {
return confirm('Are you sure you want to continue? Any unsaved changes will be lost');
}
return true;
}
}
เพิ่ม providers ใน app.module.ts
เปิดการใช้งาน CanDeactivate ใน routes.ts ในส่วนของ ‘member/edit’
canDeactivate: [PreventUnsavedChanges]
ทดสอบรัน ไปที่ Edit Profile ลองแก้ไขข้อมูล และเปลี่ยนหน้า จะพบว่ามีข้อความเตือนตามที่กำหนดไว้
สร้างฟังก์ชันเพื่อป้องกันการปิดหน้าต่างโดยไม่ได้บันทึกข้อมูล
@HostListener('window:beforeunload', ['$event'])
unloadNotification($event: any) {
if (this.editForm.dirty) {
return $event.returnValue = true;
}
}
ลองรัน และเปิดหน้า Edit Profile แล้วทำการแก้ไขข้อมูล และปิดหน้าต่างไป
4. สร้าง API สำหรับการอัพเดตข้อมูล Profile
สร้าง API โดยเริ่มจากสร้าง DTOs สำหรับรับข้อมูลที่ต้องการอัพเดต
UserForUpdateDto.cs
namespace SocialApp_API.Dtos
{
public class UserForUpdateDto
{
public string Introduction { get; set; }
public string LookingFor { get; set; }
public string Interests { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
}
เพิ่ม Auto Mapper ใน AutoMapperProfiles.cs
CreateMap<UserForUpdateDto, User>();
เพิ่ม Method สำหรับอัพเดตข้อมูลใน UsersController.cs
[HttpPut("{id}")]
public async Task<IActionResult> UpdateUser(int id, UserForUpdateDto userForUpdateDto)
{
if (id != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))
return Unauthorized();
var userFromRepo = await _repo.GetUser(id);
_mapper.Map(userForUpdateDto, userFromRepo);
if (await _repo.SaveAll())
return NoContent();
throw new System.Exception($"Updating user {id} failed on save");
}
5. อัพเดตข้อมูล Profile
เพิ่มฟังก์ชันอัพเดตข้อมูลสมาชิกใน user.service.ts
updateUser(id: number, user: User) {
return this.http.put(this.baseUrl + 'users/' + id, user);
}
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../_models/user';
@Injectable({
providedIn: 'root'
})
export class UserService {
baseUrl = environment.apiUrl;
constructor(private http: HttpClient) { }
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.baseUrl + 'users');
}
getUser(id): Observable<User> {
return this.http.get<User>(this.baseUrl + 'users/' + id);
}
updateUser(id: number, user: User) {
return this.http.put(this.baseUrl + 'users/' + id, user);
}
}
ปรับปรุงฟังก์ชันบันทึกข้อมูลสมาชิกใน member-edit.component.ts
updateUser() {
this.userService.updateUser(this.authService.decodeToken.nameid, this.user).subscribe(next => {
this.alertify.success('Profile updated successfully');
this.editForm.reset(this.user);
}, error => {
this.alertify.error(error);
});
}
import { Component, OnInit, ViewChild, HostListener } from '@angular/core';
import { User } from 'src/app/_models/user';
import { ActivatedRoute } from '@angular/router';
import { AlertifyService } from 'src/app/_services/alertify.service';
import { NgForm } from '@angular/forms';
import { UserService } from 'src/app/_services/user.service';
import { AuthService } from 'src/app/_services/auth.service';
@Component({
selector: 'app-member-edit',
templateUrl: './member-edit.component.html',
styleUrls: ['./member-edit.component.css']
})
export class MemberEditComponent implements OnInit {
@ViewChild('editForm') editForm: NgForm;
user: User;
@HostListener('window:beforeunload', ['$event'])
unloadNotification($event: any) {
if (this.editForm.dirty) {
return $event.returnValue = true;
}
}
constructor(private route: ActivatedRoute, private alertify: AlertifyService,
private userService: UserService, private authService: AuthService) { }
ngOnInit() {
this.route.data.subscribe(data => {
this.user = data.user;
});
}
updateUser() {
this.userService.updateUser(this.authService.decodeToken.nameid, this.user).subscribe(next => {
this.alertify.success('Profile updated successfully');
this.editForm.reset(this.user);
}, error => {
this.alertify.error(error);
});
}
}
ทดสอบรัน และลองแก้ไขข้อมูล
โปรดติดตามตอนต่อไป…