我正在创建一个调用Facebook javascript api的Facebook服务,并且想知道如何在我的值更新时最好地实现更改检测。
我有currentUser
,其currentUser: Subject<User> = new BehaviorSubject<User>(new User(null));
属性是BehaviorSubject:
tick()
当我想更新用户以响应facebook javascript sdk告诉我用户已登录或退出时,我更新了该内容并需要在ApplicationRef
上致电updateUser(user: User) {
console.log('UserService.updateUser:', user);
this.currentUser.next(user);
this.appRef.tick(); // UI does not update without this
}
constructor(facebook: Facebook) {
this.facebook.facebookEvents.filter(x => x != null
&& x.eventName == 'auth.authResponseChange')
.subscribe((event) => {
this.updateUser(new User(event.data));
}
}
:< / p>
<h2>Logged into Facebook as {{currentUser.value.name}}</h2>
<p>Is this you? <img src="{{currentUser.value.profilePicUrl}}"></p>
在我的组件中,我在构造函数中存储来自用户服务的'currentUser'并绑定到value属性:
constructor(userService: UserService, private ref: ApplicationRef, private zone: NgZone)
...
this.postsSubject.subscribe((post) => {
this.zone.runOutsideAngular(() => { // doesn't do anything
this.posts.push(post);
console.log('postsSubject POST, count is ', this.posts.length);
ref.tick(); // required to update bindings
});
}
我做错了吗?有没有比从外部库触发更改后调用ApplicationRef.tick()更好的方法?
我尝试使用NgZone并且无效,使用不同的事件将Feed中的帖子作为服务页面返回:
{{posts.length}}
控制台显示计数递增,但只有在我添加ref.tick()
调用时才会更新html绑定@Formula
...
我想我看到某个地方你可以从顶级应用程序组件中为任何组件提供“输入”,这可能是登录用户的方式,但不是其他调用,例如在Feed中获取帖子。 ..
答案 0 :(得分:18)
我做错了吗?有没有比从外部库触发更改后调用
ApplicationRef.tick()
更好的方法?
这取决于。如果您在Angular之外调用Facebook API(即在Angular之外注册异步事件处理程序),那么您将需要手动运行更改检测作为处理任何事件的一部分。你可以
NgZone
,然后在该对象上调用run()
,该对象将执行Angular区域内传递的(回调)函数,然后自动调用ApplicationRef().tick()
,这将运行更改检测整个应用程序,或ApplicationRef
并自行致电tick()
或ChangeDetectorRef
并自己致电detectChanges()
- 这只会对一个组件及其子组件进行更改检测注意,如果您注入NgZone
,则不想使用runOutsideAngular()
。这将在Angular区域外执行传递的(回调)函数,并且不会调用ApplicationRef().tick()
,因此不会执行更改检测。
如果你在Angular中调用Facebook API,你可能可以避免上述所有,因为然后Angular(通过使用Zone.js)应该修补异步事件调用。然后,当您的事件触发时,将自动调用ApplicationRef.tick()
。有关此方法的更多讨论,请参阅https://stackoverflow.com/a/34593821/215945。
答案 1 :(得分:13)
我不确定它是否更好。还有其他几种我能想到的方法。
您可以注入NgZone并使用回调执行run方法:
NgZone.run(()=>this.currentUser.next(user));
setTimeout将自动触发更改检测:
setTimeout(()=>this.currentUser.next(user));
答案 2 :(得分:5)
您能否按照初始化Facebook
提供商的方式向我们提供您在组件中的服务?
选项#1
您的行为让我更改了Facebook代码在Angular区域外运行,因此当事件触发时,Angular更改检测不会运行。你
您也可以手动运行更改检测:
import { Component, ChangeDetectorRef } from 'angular2/core';
@Component({
(...)
})
export class MyComponent {
constructor(private cdr:ChangeDetectorRef) {
}
someMethod() {
this.cdr.detectChanges();
}
}
请参阅以下问题:
选项#2
也许您的事件在组件在currentUser
主题上注册回调之前被触发。在这种情况下,您可以稍后触发事件......