Angular (2+) - 延迟数据绑定插值

Angular (2+) - getting a delay in data binding interpolation

我正在使用 google 的位置建议 API 构建位置搜索输入。一切正常,结果几乎是即时返回,但我在显示数据时遇到了几个问题。

我已经写了一份我在 StackBlitz 上尝试做的事情的基本副本,https://google-location-suggestions.stackblitz.io,这里仍然有同样的问题。我已将其更新为具有更好地显示问题的加载状态。

StackBlitz link 编辑: https://stackblitz.com/edit/google-location-suggestions

我还在此处添加了一段视频,以便您明白我的意思: https://vimeo.com/271476965

如果有人知道为什么会这样,我将不胜感激。

"delay"与变更检测有关,如果在进入位置搜索后点击文档,angular会获取事件并刷新DOM。

地图 api 在 angular 加载后下载,这使得地图代码 运行 在 ngZone 之外。我在阅读 .

时理解了这一点

主要修复(正如您之前在回答中提到的那样)是使用 ngZone.run 到 运行 Angular 区域中的代码:

private suggestions$ = new BehaviorSubject([]);

public search(location: string): void {
    this.service.getPlacePredictions(
      {
        input: location,
        componentRestrictions: { country: 'uk' }
      },
      (predictions, status) => this._ngZone.run(() => this.suggestions$.next(predictions.map(p => p.description)))
    );
  }

我还添加了一些其他改进:

在构造函数中只加载一次地图 api 以避免已经加载的错误(stackblitz aot 也会导致多次加载服务,所以我将重新加载机制更改为左下角菜单上的页面):

constructor(private mapsAPILoader: MapsAPILoader) {
    this.mapsAPILoader.load().then(() => {
      this.service = new google.maps.places.AutocompleteService();
      console.log('Maps API loaded');
      this.mapsApiLoading$.next(false);
    });
  }

您可以使用 rxjs 管道创建所需的可观察对象:

this.locationSuggestions$ = this.locationForm.get('location').valueChanges.pipe(
        filter(location => location && location !== ''),
        switchMap(location =>
            this.appService.getLocationSuggestions(location)));

这样您就可以使用 async 直接在模板中订阅您的 observable :

<ng-container *ngIf="locationSuggestions$ | async as suggestions; else loading">
{{ suggestions | json }}
</ng-container>
<ng-template #loading>
  loading...
</ng-template>

有时,如果我足够快,我可以在加载地图之前进行搜索 api,所以我添加了一个 loading observable,让组件知道他什么时候可以开始搜索。

Here is the new stackblitz with the changes.

@ibenjelloun(谢谢)建议的问题是变更检测。

我将 Angular 的 NgZone 实现为 运行 变化检测,以便通过将代码包装在 ngZone.run 方法中来更新绑定

this.ngZone.run(() => {
    this.locationSuggestionsLoading = false;
    this.locationSuggestions = locations;
});