为什么异步管道检测不到 Angular 中的更改(但 component.ts 中的订阅检测到)?
Why doesn't async pipe detect changes in Angular (but subscription in component.ts does)?
我在 angular 中使用异步管道来监视来自 rxjs 存储的可观察对象。组件的 ngOnInit 看起来像这样
ngOnInit() {
this.userRole$ = this.store.select(selectUserProfile).pipe(
filter(user => !!user),
map(user => parseUserRole(user.role))
);
}
组件模板如下所示
<p> User role is {{ userRole$ | async }} </p>
用户登录后,页面上的消息仍然是一个空字符串
在component.ts我添加了以下代码来调试问题
this.userRole$.subscribe(userRole => {
alert(`new user role is ${userRole}`);
});
用户登录后,我收到一条提示 "new user role is admin",但是 html 模板中的管道没有更新。
当我使用 of() 将商店 select() 替换为虚拟值时,一切都按预期工作,所以我很确定问题与 rxjs 有关。
auth reducer(正在启动)看起来像这样(
export function reducer(state = initialAuthState, action: AuthActions): AuthState {
switch (action.type) {
/// ...CODE OMITTED
case AuthActionTypes.UserProfileRetrieved:
alert(`setting user profile ${action.payload.userProfile}`)
return { ...state, userProfile: action.payload.userProfile }
default:
return state;
}
}
我已尝试确保从 ngZone.run() 内部调度 UserProfileRetrieved 操作,但这并没有什么区别。我真的不知道如何调试它。任何指针将不胜感激。谢谢!
你能试试这个代码,看看它是否工作正常。添加了 tap 运算符以查看是否发生了从商店发出的 changes/data。
this.userRole$ = this.store
.select(selectUserProfile)
.pipe(
tap(user => console.log('FETCHED:', user)), // Console if user data exists
filter(Boolean), // Change !!user to Boolean
tap(user => console.log('FILTERED:', user)), // Console if user exists after filter
map(user => parseUserRole(user.role))
tap(user => console.log('MAPPED:', user)), // Console if user is mapped
);
NOTE:
That the store will only send it's response once the prior/parent service is invoked.
示例:
// If along with the getUsers() functionality has a piped storeService in it
// http.get(url).pipe(tap(data => this.storeService.set('users', data)))
this.userService.getUsers().subscribe();
// You can then initialize your store to get the data invoked/set above
this.user$ = this.store.select('users');
这原来是由 auth0 本机应用程序登录流程的副作用引起的。应用路由器配置为使用基于哈希的路由以支持 Cordova。从 auth0 获取登录令牌后,我们正在清除哈希以删除令牌信息。在此之后的任何商店更新都不会反映在异步管道中,但在此之前的更新。
如果有人遇到类似问题,请确保在导航到 post 授权 URL 之前,清除哈希是您做的最后一件事。感谢@Shorbagy 和@KShewengger 的帮助。
这是我用来执行此操作的代码
@Effect()
loginComplete$ = this.actions$.pipe(
ofType<LoginComplete>(AuthActionTypes.LoginComplete),
exhaustMap(() => {
return this.authService.authResult$.pipe(
map((authResult: any) => {
if (environment.platform.name === Platforms.BROWSER) {
window.location.hash = '';
}
if (authResult && authResult.accessToken) {
this.authService.setAuth(authResult);
return new LoginSuccess();
} else {
debugger;
return new LoginFailure({ message: 'no accessToken', payload: authResult })
}
}),
catchError(error => of(new LoginFailure(error)))
);
})
);
我在 angular 中使用异步管道来监视来自 rxjs 存储的可观察对象。组件的 ngOnInit 看起来像这样
ngOnInit() {
this.userRole$ = this.store.select(selectUserProfile).pipe(
filter(user => !!user),
map(user => parseUserRole(user.role))
);
}
组件模板如下所示
<p> User role is {{ userRole$ | async }} </p>
用户登录后,页面上的消息仍然是一个空字符串
在component.ts我添加了以下代码来调试问题
this.userRole$.subscribe(userRole => {
alert(`new user role is ${userRole}`);
});
用户登录后,我收到一条提示 "new user role is admin",但是 html 模板中的管道没有更新。
当我使用 of() 将商店 select() 替换为虚拟值时,一切都按预期工作,所以我很确定问题与 rxjs 有关。
auth reducer(正在启动)看起来像这样(
export function reducer(state = initialAuthState, action: AuthActions): AuthState {
switch (action.type) {
/// ...CODE OMITTED
case AuthActionTypes.UserProfileRetrieved:
alert(`setting user profile ${action.payload.userProfile}`)
return { ...state, userProfile: action.payload.userProfile }
default:
return state;
}
}
我已尝试确保从 ngZone.run() 内部调度 UserProfileRetrieved 操作,但这并没有什么区别。我真的不知道如何调试它。任何指针将不胜感激。谢谢!
你能试试这个代码,看看它是否工作正常。添加了 tap 运算符以查看是否发生了从商店发出的 changes/data。
this.userRole$ = this.store
.select(selectUserProfile)
.pipe(
tap(user => console.log('FETCHED:', user)), // Console if user data exists
filter(Boolean), // Change !!user to Boolean
tap(user => console.log('FILTERED:', user)), // Console if user exists after filter
map(user => parseUserRole(user.role))
tap(user => console.log('MAPPED:', user)), // Console if user is mapped
);
NOTE:
That the store will only send it's response once the prior/parent service is invoked.
示例:
// If along with the getUsers() functionality has a piped storeService in it
// http.get(url).pipe(tap(data => this.storeService.set('users', data)))
this.userService.getUsers().subscribe();
// You can then initialize your store to get the data invoked/set above
this.user$ = this.store.select('users');
这原来是由 auth0 本机应用程序登录流程的副作用引起的。应用路由器配置为使用基于哈希的路由以支持 Cordova。从 auth0 获取登录令牌后,我们正在清除哈希以删除令牌信息。在此之后的任何商店更新都不会反映在异步管道中,但在此之前的更新。
如果有人遇到类似问题,请确保在导航到 post 授权 URL 之前,清除哈希是您做的最后一件事。感谢@Shorbagy 和@KShewengger 的帮助。
这是我用来执行此操作的代码
@Effect()
loginComplete$ = this.actions$.pipe(
ofType<LoginComplete>(AuthActionTypes.LoginComplete),
exhaustMap(() => {
return this.authService.authResult$.pipe(
map((authResult: any) => {
if (environment.platform.name === Platforms.BROWSER) {
window.location.hash = '';
}
if (authResult && authResult.accessToken) {
this.authService.setAuth(authResult);
return new LoginSuccess();
} else {
debugger;
return new LoginFailure({ message: 'no accessToken', payload: authResult })
}
}),
catchError(error => of(new LoginFailure(error)))
);
})
);