I have two components. users.components.ts and register.components.ts. users.components.ts displays a table of users and register.components.ts is where we add/edit users.
When we add/edit the user the users is redirected back to the users.components.ts via router.navigate(). However, the changes are not seen in the users table until the page is refreshed.
This seems to be a common problem, but i still can't find a solution. Here is my code
app-routing.module.ts
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { RegisterComponent } from './components/register/register.component';
import { UsersComponent } from './components/users/users.component';
const routes: Routes = [
{ path: 'users', component: UsersComponent, canActivate: [AdminGuard] },
{ path: 'register', component: RegisterComponent, canActivate: [AdminGuard] },
{ path: 'login', component: LoginComponent },
// otherwise redirect to users
{ path: '**', redirectTo: 'users' }
];
export const AppRouting = RouterModule.forRoot(routes);
users.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { first } from 'rxjs/operators'; // What is this? Look it up
import { MatPaginator, MatTableDataSource,
MatDialog, MatDialogConfig
} from '@angular/material';
import { User } from './../../models/user';
import { UserService } from './../../services/user.service';
import { AlertService } from './../../services/alert.service';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss']
})
export class UsersComponent implements OnInit {
loading = false;
displayedColumns: string[] = [
'id',
'name',
'email',
'contactNumber',
'lastActive',
'edit'
];
users: User[] = [];
dataSource = new MatTableDataSource<User>();
@ViewChild(MatPaginator) paginator: MatPaginator;
constructor(
private router: Router,
private route: ActivatedRoute,
private userService: UserService,
private alertService: AlertService
) {
this.loadUsers();
this.dataSource.paginator = this.paginator;
}
editUser(user: User): void {
this.clear();
window.localStorage.setItem('editUserId', user.id.toString());
this.router.navigate(['register']);
}
addUser(): void {
this.clear();
this.router.navigate(['register']);
}
private async loadUsers() {
this.loading = true;
try {
this.users = await this.userService.get().toPromise();
this.dataSource = new MatTableDataSource<User>(this.users);
} catch (error) {
this.alertService.error(error);
}
this.loading = false;
}
private clear() {
window.localStorage.removeItem('editUserId');
}
}
register.component.ts
import { Component, OnInit } from '@angular/core';
import { first } from 'rxjs/operators';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { User } from './../../models/user';
import { CheckUsernameEmailRequest } from 'src/app/models/check.username.email.request';
import { UserService } from './../../services/user.service';
import { AlertService } from './../../services/alert.service';
import { ValidationService } from './../../services/validation.service';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit {
editUserId: string;
userForm: FormGroup;
loading = false;
submitted = false;
constructor(
private formBuilder: FormBuilder,
private router: Router,
private userService: UserService,
private alertService: AlertService,
private validationService: ValidationService
) { }
ngOnInit() {
this.editUserId = window.localStorage.getItem('editUserId');
const checkUsernameEmailRequest: CheckUsernameEmailRequest = <CheckUsernameEmailRequest>({
userId: this.editUserId,
usernameOrEmail: ''
});
this.userForm = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
contactNumber: this.validationService.phoneNumberValidators(),
email: this.validationService.emailValidators(checkUsernameEmailRequest),
username: this.validationService.usernameValidators(checkUsernameEmailRequest),
password: ['', Validators.required],
admin: false
});
if (this.editUserId) {
this.loadUser();
}
}
// convenience getter for easy access to form fields
get controls() { return this.userForm.controls; }
getErrorMessage(formControl: FormControl) {
return this.validationService.getErrorMessage(formControl);
}
public onSubmit() {
this.submitted = true;
if (this.userForm.invalid) { return; }
this.loading = true;
const user: User = <User>({
firstName: this.controls.firstName.value,
lastName: this.controls.lastName.value,
contactNumber: this.controls.contactNumber.value,
email: this.controls.email.value,
username: this.controls.username.value,
password: this.controls.password.value,
admin: this.controls.admin.value
});
if (this.editUserId) {
this.edit(user);
} else {
this.register(user);
}
this.router.navigate(['users']);
}
private populateForm(user: any) {
this.controls.firstName.setValue(user.firstName);
this.controls.lastName.setValue(user.lastName);
this.controls.contactNumber.setValue(user.contactNumber);
this.controls.email.setValue(user.email);
this.controls.username.setValue(user.username);
this.controls.password.setValue(user.password);
this.controls.admin.setValue(user.admin);
}
private loadUser() {
this.userService
.getById(+this.editUserId) // + operator is a quick way to convert a string to int
.pipe(first())
.subscribe(data => {
this.populateForm(data);
}, error => {
this.alertService.error(error);
this.loading = false;
});
}
private register(user: User) {
this.userService
.register(user)
.pipe(first())
.subscribe(data => {
this.alertService.handleResponse(data);
}, error => {
this.alertService.error(error);
this.loading = false;
});
}
private edit(user: User) {
user.id = +this.editUserId;
this.userService
.update(user)
.pipe(first())
.subscribe(data => {
this.alertService.handleResponse(data);
}, error => {
this.alertService.error(error);
this.loading = false;
});
window.localStorage.removeItem('editUserId');
}
}
user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { User } from './../models/user';
import { ApiResponse } from './../models/api.response';
import { environment } from 'src/environments/environment';
@Injectable({ providedIn: 'root' })
export class UserService {
apiUrl: string = environment.apiUrl;
constructor(private http: HttpClient) { }
get() {
return this.http.get<User[]>(`${this.apiUrl}/users`);
}
getById(id: number) {
return this.http.get(`${this.apiUrl}/users/${id}`);
}
register(user: User) {
return this.http.post<ApiResponse>(`${this.apiUrl}/users/register`, user);
}
update(user: User) {
return this.http.put<ApiResponse>(`${this.apiUrl}/users/edit`, user);
}
}
you are redirecting synchronously, after call of edit/register method, try to redirect in subscribe callback of those methods