Angular2 ChangeDetection 还是 Observable?
Angular2 ChangeDetection or Observable?
我在使用登录时不刷新的组件时遇到问题。
组件是 navbar.component,其中包含 link 到我的 pages/components。在它上面,有一个呈现 login.component 的 "login" link,我可以在上面提供用户名和密码,然后单击登录按钮。 login.component 使用 user.service 使用 login.component 提供的用户名和密码调用后端,存储收到的令牌并重定向到“/”。
此时,navbar.component 上的 "login" link 应该被隐藏,而 "logout" link 应该显示,但是直到我点击一个时什么都没有发生导航栏上的其他 link 个。
2个link如下:
<a [hidden]="userService.isLoggedIn" [routerLink]="['Login']">Login</a>
<a [hidden]="!userService.isLoggedIn" (click)="userService.logout();" href="javascript:void(0)">Logout</a>
我知道存储令牌并从 user.service 重定向不会触发更改检测,而且我的 属性 userService.isLoggedIn 不是可观察的,所以我知道我是遗漏了一些东西,但不确定 is/should 的方法是什么。
我曾尝试注入 ApplicationRef 来调用 tick() 方法,希望这会触发更改检测,但失败了。
我应该让我的 属性 userService.isLoggedIn 成为可观察对象吗?
export class UserService {
isLoggedIn:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
}
@Component({
...
template: `
<a [hidden]="userService.isLoggedIn | async" [routerLink]="['Login']">Login</a>
<a [hidden]="!(userService.isLoggedIn | async)" (click)="userService.logout();" href="javascript:void(0)">Logout</a>
`
})
export class MyComponent {
constructor(private userService: UserService) {}
}
I understand storing the token and redirecting from user.service doesn't trigger change detection
是的,但是如果您使用的是 Angular Http 服务,当从该服务返回数据时,更改检测应该 运行 在您的回调 function/method 执行之后。您的导航栏组件是否使用 OnPush
更改检测策略? (如果是这样,那就可以解释为什么不更新了。)
Günter 的回答是有效的,因为异步管道不仅自动 subscribe()
s 到 observable,而且当 observable 发出新值时它还会调用 markForCheck()
。这确保组件(及其所有祖先)将被检测到更改,即使它们中的任何一个正在使用 OnPush
.
另一种方法更具命令性(而不是声明性),它仍然使用 BehaviorSubject,如下所示:
- 将 ChangeDetectorRef 注入您的导航栏组件
subscribe()
到服务 observable
- 当 observable 触发时,调用
detectChanges()
。这将检查组件及其子组件(如果有的话)。这可能比使用 markForCheck()
更有效,尤其是在 NavBar 没有任何子项的情况下。但考虑到日志记录 in/out 可能是罕见事件,效率可能并不重要。但是,我更喜欢在仅更改 view/component 状态时使用 detectChanges()
(就像这里的情况,基于我在下面的实现方式)而不是应用程序状态——即影响多个组件的东西, 因此 markForCheck()
会更合适。
@Component({
...
template: `
<a [hidden]="userIsLoggedIn" [routerLink]="['Login']">Login</a>
<a [hidden]="!userILoggedIn" (click)="userService.logout()">Logout</a>
`
})
export class NavBar {
userIsLoggedIn = false;
constructor(private userService: UserService, private _ref: ChangeDetectorRef) {}
ngOnInit() {
this.userService.isLoggedIn.subscribe( userIsLoggedIn => {
this.userIsLoggedIn = userIsLoggedIn;
this._ref.detectChanges();
});
}
}
我在使用登录时不刷新的组件时遇到问题。
组件是 navbar.component,其中包含 link 到我的 pages/components。在它上面,有一个呈现 login.component 的 "login" link,我可以在上面提供用户名和密码,然后单击登录按钮。 login.component 使用 user.service 使用 login.component 提供的用户名和密码调用后端,存储收到的令牌并重定向到“/”。
此时,navbar.component 上的 "login" link 应该被隐藏,而 "logout" link 应该显示,但是直到我点击一个时什么都没有发生导航栏上的其他 link 个。
2个link如下:
<a [hidden]="userService.isLoggedIn" [routerLink]="['Login']">Login</a>
<a [hidden]="!userService.isLoggedIn" (click)="userService.logout();" href="javascript:void(0)">Logout</a>
我知道存储令牌并从 user.service 重定向不会触发更改检测,而且我的 属性 userService.isLoggedIn 不是可观察的,所以我知道我是遗漏了一些东西,但不确定 is/should 的方法是什么。
我曾尝试注入 ApplicationRef 来调用 tick() 方法,希望这会触发更改检测,但失败了。
我应该让我的 属性 userService.isLoggedIn 成为可观察对象吗?
export class UserService {
isLoggedIn:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
}
@Component({
...
template: `
<a [hidden]="userService.isLoggedIn | async" [routerLink]="['Login']">Login</a>
<a [hidden]="!(userService.isLoggedIn | async)" (click)="userService.logout();" href="javascript:void(0)">Logout</a>
`
})
export class MyComponent {
constructor(private userService: UserService) {}
}
I understand storing the token and redirecting from user.service doesn't trigger change detection
是的,但是如果您使用的是 Angular Http 服务,当从该服务返回数据时,更改检测应该 运行 在您的回调 function/method 执行之后。您的导航栏组件是否使用 OnPush
更改检测策略? (如果是这样,那就可以解释为什么不更新了。)
Günter 的回答是有效的,因为异步管道不仅自动 subscribe()
s 到 observable,而且当 observable 发出新值时它还会调用 markForCheck()
。这确保组件(及其所有祖先)将被检测到更改,即使它们中的任何一个正在使用 OnPush
.
另一种方法更具命令性(而不是声明性),它仍然使用 BehaviorSubject,如下所示:
- 将 ChangeDetectorRef 注入您的导航栏组件
subscribe()
到服务 observable- 当 observable 触发时,调用
detectChanges()
。这将检查组件及其子组件(如果有的话)。这可能比使用markForCheck()
更有效,尤其是在 NavBar 没有任何子项的情况下。但考虑到日志记录 in/out 可能是罕见事件,效率可能并不重要。但是,我更喜欢在仅更改 view/component 状态时使用detectChanges()
(就像这里的情况,基于我在下面的实现方式)而不是应用程序状态——即影响多个组件的东西, 因此markForCheck()
会更合适。
@Component({
...
template: `
<a [hidden]="userIsLoggedIn" [routerLink]="['Login']">Login</a>
<a [hidden]="!userILoggedIn" (click)="userService.logout()">Logout</a>
`
})
export class NavBar {
userIsLoggedIn = false;
constructor(private userService: UserService, private _ref: ChangeDetectorRef) {}
ngOnInit() {
this.userService.isLoggedIn.subscribe( userIsLoggedIn => {
this.userIsLoggedIn = userIsLoggedIn;
this._ref.detectChanges();
});
}
}