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,让组件知道他什么时候可以开始搜索。
@ibenjelloun(谢谢)建议的问题是变更检测。
我将 Angular 的 NgZone 实现为 运行 变化检测,以便通过将代码包装在 ngZone.run
方法中来更新绑定
this.ngZone.run(() => {
this.locationSuggestionsLoading = false;
this.locationSuggestions = locations;
});
我正在使用 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,让组件知道他什么时候可以开始搜索。
@ibenjelloun(谢谢)建议的问题是变更检测。
我将 Angular 的 NgZone 实现为 运行 变化检测,以便通过将代码包装在 ngZone.run
方法中来更新绑定
this.ngZone.run(() => {
this.locationSuggestionsLoading = false;
this.locationSuggestions = locations;
});