Привязка не обновляется при изменении свойства компонента в обратном вызове - PullRequest
2 голосов
/ 01 мая 2019

Я создаю расширение Chrome с Angular для рендеринга всплывающего окна. Привязка к представлению не обновляется, когда обратный вызов поступает из Chrome API, а свойство, используемое в привязке к представлению, изменяется в результате этого обратного вызова. Добавляя дополнительные сложности, обратный вызов не вызывается напрямую, а оборачивается в Observable.

Если я позвоню ChangeDetectorRef.detectChanges(), то представление обновляется соответствующим образом. Я попытался использовать NgZone, но я могу использовать его неправильно - это не даст никакого эффекта, если я включу его или исключу из метода, который создает мою наблюдаемую.

Соответствующий код компонента

ngOnInit() {
  this.port = chrome.runtime.connect({ name: 'PopupToBackground' });
  // ChromeUtil is an injected service wrapping chrome API calls.
  this.chromeUtil.portOnMessage$(this.port).pipe(
    tap((x: string) => {
      // text is the bound property
      this.text = x || 'no data';
      // Uncomment line below and everything works.
      //this.cd.detectChanges();
    })
  ).subscribe();
}

Соответствующий код ChromeUtil

@Injectable({ providedIn: 'root' })
export class ChromeUtil {
  constructor(private zone: NgZone) { }

  portOnMessage$(port: chrome.runtime.Port) {
    return new Observable<any>(subscriber => {
      return this.zone.run(() => {
        const listener = (msg: any) => subscriber.next(msg);
        port.onMessage.addListener(listener);
        return { 
          unsubscribe() { 
            port.onMessage.removeListener(listener); 
          } 
        };
      });
    });
  }
}

1 Ответ

1 голос
/ 01 мая 2019

События onMessage выполняются вне Angular, и вам нужно вызвать zone.run(), чтобы активировать обнаружение изменений.Он у вас почти есть, но вы вызываете run() в неправильной точке.

portOnMessage$(port: chrome.runtime.Port) {
    return new Observable<any>(subscriber => {
        const listener = (msg: any) => this.zone.run(() => subscriber.next(msg));
        port.onMessage.addListener(listener);
        return {
            unsubscribe() {
                port.onMessage.removeListener(listener);
            }
        };
    });
}

Обратный вызов, переданный port.onMessage.addListener(), выполняется вне Angular.Именно этот обратный вызов должен выполняться внутри зоны.

  // Uncomment line below and everything works.
  //this.cd.detectChanges();

Если ваш компонент использует OnPush обнаружение изменений, то вам придется вызывать this.cd.markForCheck(), как если бы вы использовали любую внешнюю наблюдаемую длясоставная часть.Альтернативой является использование в шаблоне трубы async.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...