Angular 路由器导航在之前的代码行之前执行
Angular router navigate perform before previous code lines
我的 angular 代码遇到了一个奇怪的问题。
我有一个调用 API.
的登录页面
login.component.ts:
export class LoginComponent implements OnInit {
formData;
constructor(private usersService: UsersService, private router: Router) { }
ngOnInit() {
this.formData = new FormGroup({
login: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required])
});
}
onClickSubmit(data) {
this.usersService.login(data).subscribe((response) => {
const token = response.token;
const userLogin = response.user.userLogin;
localStorage.setItem('token', token);
localStorage.setItem('login', userLogin);
this.router.navigate(['/home']);
});
}
}
login.component.html:
<div class="card mb-3">
<div class="card-header">
Login
</div>
<div class="card-body">
<form [formGroup]="formData" (ngSubmit)="onClickSubmit(formData.value)" novalidate>
<div class="form-group">
<label for="inputLogin">Login</label>
<input type="text" class="form-control" id="inputLogin" name="login" placeholder="Login" formControlName="login">
<span *ngIf="(login.dirty || login.touched) && login.invalid && login.errors.required" class="error">Login is required</span>
</div>
<div class="form-group">
<label for="inputPassword">Password</label>
<input type="password" class="form-control" id="inputPassword" name="password" placeholder="Password" formControlName="password">
<span *ngIf="(password.dirty || password.touched) && password.invalid && password.errors.required" class="error">Login is required</span>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!formData.valid">Sign in</button>
</form>
</div>
<p class="card-text login-text"><small class="text-muted">Don't have any account? <a routerLink="/register">Register</a></small></p>
</div>
我注意到 this.router.navigate()
在我的 localStorage.setIem
之前执行。
users.service.ts:
export class UsersService {
private apiUrl = 'https://localhost:63939/api/v1/';
private registerUrl = this.apiUrl + 'identity/register';
private loginUrl = this.apiUrl + 'identity/login';
constructor(private httpClient: HttpClient) { }
register(user: User): Observable<AuthResponse> {
return this.httpClient.post<AuthResponse>(this.registerUrl, user);
}
login(user: LoginRequest): Observable<AuthResponse> {
return this.httpClient.post<AuthResponse>(this.loginUrl, user);
}
}
menu.component.ts:
export class MenuComponent implements OnInit {
showLoginLink = true;
userLogin;
constructor() { }
ngOnInit() {
this.userLogin = localStorage.getItem('login');
if (this.userLogin !== null) {
this.showLoginLink = false;
}
}
}
menu.component.html
<li class="nav-item" *ngIf="showLoginLink">
<a class="nav-link" routerLink="/register">Login / Register</a>
</li>
<li class="nav-item" *ngIf="userLogin">
<a class="nav-link" routerLink="/register">{{userLogin}}</a>
</li>
执行导航时,会显示菜单,但 localStorage 为空,因此我的 userLogin 为空,我的 *ngIf="userLogin"
不起作用。重定向后立即填充 localStorage,如果我刷新页面,我有我的值并且我的菜单有效(显示我的第二个 <li>
而不是第一个)。
这是标准行为吗?如何在不刷新页面的情况下实现菜单更改?
(我更喜欢解释而不是现成的解决方案,但我不拒绝解决方案^-^)
编辑:根据评论添加一些代码 :) 如果需要更多代码,我会再次编辑
这是因为 ngOnInit
在 onClickSubmit
触发之前被调用了一次。所以 userLogin
不会更新。
您需要以某种方式通知 MenuComponent
userLogin
值已经更改
发生这种情况是因为在本地存储中写入数据需要花费大量时间,因此您的导航是在数据可用并可以检索之前执行的。
您可以通过在导航到“/home”路由之前设置超时或通过在 usersService 中添加属性来避免这种情况,这样值将在成功登录后立即可用。
这是因为您的导航到主页组件和 "menu" 组件在登录组件之前加载。
您可以使用观察器让菜单组件知道登录已执行。
首先,您将创建一个服务,我们称它为 AuthService
@Injectable()
export class AuthService {
public loginPreformedObserver: Subject<any> = new Subject<any>();
}
然后在您的登录组件中
export class LoginComponent implements OnInit {
formData;
constructor(private usersService: UsersService, private router:
Router,private authService: AuthService)
{
}
ngOnInit() {
this.formData = new FormGroup({
login: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required])
});
}
onClickSubmit(data) {
this.usersService.login(data).subscribe((response) => {
const token = response.token;
const userLogin = response.user.userLogin;
localStorage.setItem('token', token);
localStorage.setItem('login', userLogin);
this.authService.loginPreformedObserver.next();
this.router.navigate(['/home']);
});
}
}
然后在您的菜单组件中
export class MenuComponent implements OnInit {
showLoginLink = true;
userLogin;
private _loginPreformed: Subject<any>;
constructor(private authService: AuthService) { }
ngOnInit() {
this._loginPreformed= this.authService.loginPreformedObserver;
this._loginPreformed.subscribe(
value =>
{
this.userLogin = localStorage.getItem('login');
if (this.userLogin !== null)
{
this.showLoginLink = false;
}
});
}
}
更多详情请看这里link
我的 angular 代码遇到了一个奇怪的问题。 我有一个调用 API.
的登录页面login.component.ts:
export class LoginComponent implements OnInit {
formData;
constructor(private usersService: UsersService, private router: Router) { }
ngOnInit() {
this.formData = new FormGroup({
login: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required])
});
}
onClickSubmit(data) {
this.usersService.login(data).subscribe((response) => {
const token = response.token;
const userLogin = response.user.userLogin;
localStorage.setItem('token', token);
localStorage.setItem('login', userLogin);
this.router.navigate(['/home']);
});
}
}
login.component.html:
<div class="card mb-3">
<div class="card-header">
Login
</div>
<div class="card-body">
<form [formGroup]="formData" (ngSubmit)="onClickSubmit(formData.value)" novalidate>
<div class="form-group">
<label for="inputLogin">Login</label>
<input type="text" class="form-control" id="inputLogin" name="login" placeholder="Login" formControlName="login">
<span *ngIf="(login.dirty || login.touched) && login.invalid && login.errors.required" class="error">Login is required</span>
</div>
<div class="form-group">
<label for="inputPassword">Password</label>
<input type="password" class="form-control" id="inputPassword" name="password" placeholder="Password" formControlName="password">
<span *ngIf="(password.dirty || password.touched) && password.invalid && password.errors.required" class="error">Login is required</span>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!formData.valid">Sign in</button>
</form>
</div>
<p class="card-text login-text"><small class="text-muted">Don't have any account? <a routerLink="/register">Register</a></small></p>
</div>
我注意到 this.router.navigate()
在我的 localStorage.setIem
之前执行。
users.service.ts:
export class UsersService {
private apiUrl = 'https://localhost:63939/api/v1/';
private registerUrl = this.apiUrl + 'identity/register';
private loginUrl = this.apiUrl + 'identity/login';
constructor(private httpClient: HttpClient) { }
register(user: User): Observable<AuthResponse> {
return this.httpClient.post<AuthResponse>(this.registerUrl, user);
}
login(user: LoginRequest): Observable<AuthResponse> {
return this.httpClient.post<AuthResponse>(this.loginUrl, user);
}
}
menu.component.ts:
export class MenuComponent implements OnInit {
showLoginLink = true;
userLogin;
constructor() { }
ngOnInit() {
this.userLogin = localStorage.getItem('login');
if (this.userLogin !== null) {
this.showLoginLink = false;
}
}
}
menu.component.html
<li class="nav-item" *ngIf="showLoginLink">
<a class="nav-link" routerLink="/register">Login / Register</a>
</li>
<li class="nav-item" *ngIf="userLogin">
<a class="nav-link" routerLink="/register">{{userLogin}}</a>
</li>
执行导航时,会显示菜单,但 localStorage 为空,因此我的 userLogin 为空,我的 *ngIf="userLogin"
不起作用。重定向后立即填充 localStorage,如果我刷新页面,我有我的值并且我的菜单有效(显示我的第二个 <li>
而不是第一个)。
这是标准行为吗?如何在不刷新页面的情况下实现菜单更改? (我更喜欢解释而不是现成的解决方案,但我不拒绝解决方案^-^)
编辑:根据评论添加一些代码 :) 如果需要更多代码,我会再次编辑
这是因为 ngOnInit
在 onClickSubmit
触发之前被调用了一次。所以 userLogin
不会更新。
您需要以某种方式通知 MenuComponent
userLogin
值已经更改
发生这种情况是因为在本地存储中写入数据需要花费大量时间,因此您的导航是在数据可用并可以检索之前执行的。 您可以通过在导航到“/home”路由之前设置超时或通过在 usersService 中添加属性来避免这种情况,这样值将在成功登录后立即可用。
这是因为您的导航到主页组件和 "menu" 组件在登录组件之前加载。
您可以使用观察器让菜单组件知道登录已执行。
首先,您将创建一个服务,我们称它为 AuthService
@Injectable()
export class AuthService {
public loginPreformedObserver: Subject<any> = new Subject<any>();
}
然后在您的登录组件中
export class LoginComponent implements OnInit {
formData;
constructor(private usersService: UsersService, private router:
Router,private authService: AuthService)
{
}
ngOnInit() {
this.formData = new FormGroup({
login: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required])
});
}
onClickSubmit(data) {
this.usersService.login(data).subscribe((response) => {
const token = response.token;
const userLogin = response.user.userLogin;
localStorage.setItem('token', token);
localStorage.setItem('login', userLogin);
this.authService.loginPreformedObserver.next();
this.router.navigate(['/home']);
});
}
}
然后在您的菜单组件中
export class MenuComponent implements OnInit {
showLoginLink = true;
userLogin;
private _loginPreformed: Subject<any>;
constructor(private authService: AuthService) { }
ngOnInit() {
this._loginPreformed= this.authService.loginPreformedObserver;
this._loginPreformed.subscribe(
value =>
{
this.userLogin = localStorage.getItem('login');
if (this.userLogin !== null)
{
this.showLoginLink = false;
}
});
}
}
更多详情请看这里link