TypeScript - Los componentes de Angular no se actualizan después de router.navigate
Tengo dos componentes. users.components.ts y register.components.ts. users.components.ts muestra una tabla de usuarios y register.components.ts es donde agregamos/editar usuarios.
Cuando añadimos/editar el usuario, los usuarios son redirigidos de vuelta a users.components.ts mediante router.navigate(). Sin embargo, los cambios no se ven en la tabla de usuarios hasta que se actualiza la página.
Esto parece ser un problema común, pero aún no puedo encontrar una solución. Aquí está mi código
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);
usuarios.componente.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');
}
}
usuario.servicio.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);
}
}
Respuesta #1
estás redirigiendo de manera sincrónica, después de la llamada al método edit/register, intenta redirigir en el callback de suscripción de esos métodos
Respuesta #2
la razón de ese comportamiento podría ser que en tu UsersComponent llamas al método loadUsers() en el constructor en lugar de en ngOnInit().
Intenta mover este método a ngOnInit().