“延迟”与变化检测有关,如果你在输入位置搜索后点击文档,angular会获取事件并刷新DOM。
地图 api 在角度加载后下载,这使得地图代码在 ngZone 之外运行。我在阅读this post 时理解了这一点。
主要解决方法(正如您之前在回答中提到的)是使用 ngZone.run 在 Angular Zone 中运行代码:
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)))
);
}
我还添加了一些其他改进:
在构造函数中只加载一次maps 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 管道创建所需的 observable:
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.