如何在Angular2中触发变化检测?

Jas*_*aat 15 typescript angular2-changedetection angular

我正在创建一个调用Facebook javascript api的Facebook服务,并且想知道如何在我的值更新时最好地实现更改检测.

我有一个UserService具有currentUser属性,它是一个BehaviorSubject:

currentUser: Subject<User> = new BehaviorSubject<User>(new User(null));
Run Code Online (Sandbox Code Playgroud)

而当我想以响应的JavaScript SDK告诉我,在用户登录或注销Facebook的更新用户,我更新,需要调用tick()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));
      }
}
Run Code Online (Sandbox Code Playgroud)

在我的组件中,我在构造函数中存储来自用户服务的'currentUser'并绑定到value属性:

<h2>Logged into Facebook as {{currentUser.value.name}}</h2>
<p>Is this you? &nbsp; <img src="{{currentUser.value.profilePicUrl}}"></p>
Run Code Online (Sandbox Code Playgroud)

难道我做错了什么?有没有比从外部库触发更改后调用ApplicationRef.tick()更好的方法?

编辑

我尝试使用NgZone并且不起作用,使用不同的事件返回Feed中的帖子作为服务页面通过它们:

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
  });
}
Run Code Online (Sandbox Code Playgroud)

控制台显示计数递增,但{{posts.length}}只有在我添加ref.tick()调用时才更新html绑定...

我想我看到某个地方你可以从顶级应用程序组件中为任何组件提供"输入",这可能是登录用户的方式,但不是其他调用,例如在Feed中获取帖子...

Mar*_*cok 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()将自动调用.有关此方法的更多讨论,请参阅/sf/answers/2421567501/.


pix*_*its 13

我不确定它是否更好.还有其他几种我能想到的方法.

使用NgZone

您可以注入NgZone并使用回调执行run方法:

 NgZone.run(()=>this.currentUser.next(user));
Run Code Online (Sandbox Code Playgroud)

使用setTimeout

setTimeout将自动触发更改检测:

setTimeout(()=>this.currentUser.next(user));
Run Code Online (Sandbox Code Playgroud)


Thi*_*ier 5

您能否以初始化Facebook提供商的方式向您提供您在组件中的服务?

选项1

您的行为使我更改了Facebook代码在Angular区域外运行,因此当事件触发时,Angular更改检测不会运行.您

您也可以手动运行更改检测:

import { Component, ChangeDetectorRef } from 'angular2/core';

@Component({
  (...)
})
export class MyComponent {
  constructor(private cdr:ChangeDetectorRef) {
  }

  someMethod() {
    this.cdr.detectChanges();
  }
}
Run Code Online (Sandbox Code Playgroud)

看到这些问题:

选项#2

也许您的事件在组件注册currentUser主题回调之前被触发.在这种情况下,您可以稍后触发事件...


归档时间:

查看次数:

30290 次

最近记录:

9 年,10 月 前