Подтвердить что ты не робот

Как вызвать обнаружение изменений в Angular2?

Я создаю службу Facebook, которая вызывает JavaScript javascript в Facebook, и мне интересно, как лучше всего реализовать обнаружение изменений, когда мои значения обновляются.

У меня есть UserService, у которого есть свойство currentUser, которое является объектом BehaviorSubject:

currentUser: Subject<User> = new BehaviorSubject<User>(new User(null));

И когда я хочу обновить пользователя в ответ на 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));
      }
}

В моем компоненте я сохраняю "currentUser" из пользовательской службы в конструкторе и привязываюсь к свойству value:

<h2>Logged into Facebook as {{currentUser.value.name}}</h2>
<p>Is this you? &nbsp; <img src="{{currentUser.value.profilePicUrl}}"></p>

Я что-то делаю неправильно? Есть ли лучший способ, чем вызвать ApplicationRef.tick() после изменения, вызванного из внешней библиотеки?

Изменить

Я попытался использовать NgZone, и это не сработает, используя другое событие, которое возвращает сообщения в фиде в качестве служебных страниц через них:

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
  });
}

Консоль показывает увеличение счетчика, но привязка html {{posts.length}} обновляется только в том случае, если я добавляю вызов ref.tick()...

Я думаю, что я где-то видел, что вы можете сделать доступными "входы" для любого компонента из компонента приложения верхнего уровня, который может быть способом для входа в систему пользователя, но не для других вызовов, таких как получение сообщений в фиде...

4b9b3361

Ответ 1

Я что-то делаю неправильно? Есть ли лучший способ, чем вызов ApplicationRef.tick() после изменения, вызванного из внешней библиотеки?

Это зависит. Если вы вызываете API Facebook вне Angular (т.е. Регистрируете асинхронные обработчики событий вне Angular), вам необходимо вручную запустить обнаружение изменений как часть обработки любых событий. Вы можете либо

  • введите NgZone, а затем вызовите run() на этом объекте, который будет выполнять переданную функцию (callback) внутри зоны Angular, а затем автоматически вызовет ApplicationRef().tick(), которая будет запускать обнаружение изменений для всего приложения, или
  • введите ApplicationRef и вызовите tick() самостоятельно, или
  • введите ChangeDetectorRef и вызовите detectChanges() самостоятельно - это приведет только к обнаружению изменений для одного компонента и его дочерних элементов

Обратите внимание: если вы введете NgZone, вы не захотите использовать runOutsideAngular(). Это выполнит переданную (обратную) функцию вне зоны Angular и не вызовет ApplicationRef().tick(), поэтому обнаружение изменений не будет выполнено.

Если вы вызываете API-интерфейсы Facebook внутри Angular, вы можете избежать всего вышеперечисленного, потому что тогда Angular (посредством использования Zone.js) должен обезопасить асинхронные вызовы событий. Затем, когда ваши события срабатывают, ApplicationRef.tick() будет вызываться автоматически. Подробнее об этом подходе см. fooobar.com/questions/313522/....

Ответ 2

Я не уверен, если это будет лучше. Есть несколько других способов, о которых я могу думать.

Использование NgZone

Вы можете ввести NgZone и выполнить метод run с обратным вызовом:

 NgZone.run(()=>this.currentUser.next(user));

Использование setTimeout

setTimeout автоматически инициирует обнаружение изменений:

setTimeout(()=>this.currentUser.next(user));

Ответ 3

Не могли бы вы дать нам способ инициализации поставщика 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. В этом случае вы можете запустить событие позже...