我尝试在Angular 2中使用Google Places和Observables。
为此,我在 index.html 中添加了Google脚本,然后从http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
获得了Observables的一些灵感。<!-- Script included in index.html -->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
您可以在那里看到整个应用程序:https://embed.plnkr.co/LQaag2/
我认为事件存在问题。例如,当用户键入“P”时,不显示任何内容。但如果他点击页面或输入“a”,他就会看到以“P”开头的地方结果。
你知道为什么吗?
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap'
platformBrowserDynamic().bootstrapModule(AppModule);
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { JsonpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { GoogleSearchComponent } from './google-search.component'
import { GoogleService } from './google.service';
@NgModule({
imports: [BrowserModule, JsonpModule, ReactiveFormsModule],
declarations: [AppComponent, GoogleSearchComponent],
providers: [GoogleService],
bootstrap: [AppComponent]
})
export class AppModule {}
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent { }
<google-search></google-search>
export class GooglePlace {
constructor(public id: string,
public description: string
) {}
}
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { GoogleService } from './google.service';
import { GooglePlace } from './google-place';
@Component({
selector: 'google-search',
template: `
<div>
<h2>Google Search</h2>
<input type="text" [formControl]="term">
<ul>
<li *ngFor="let item of items | async">{{item.description}}</li>
</ul>
</div>
`
})
export class GoogleSearchComponent {
items: Observable<Array<GooglePlace>>;
term = new FormControl();
constructor(private googleService: GoogleService) {}
ngOnInit() {
this.items = this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.switchMap(term => this.googleService.search(term));
}
}
import { Injectable } from '@angular/core';
import { GooglePlace } from './google-place';
import { Observable } from 'rxjs/Observable';
declare var google: any;
@Injectable()
export class GoogleService {
search(term: string) {
return new Observable<GooglePlace[]>(observer => {
let result: GooglePlace[] = [];
let displaySuggestions = function(predictions: any, status: string) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
predictions.forEach(function(prediction: any) {
result.push(new GooglePlace(prediction.place_id, prediction.description));
});
observer.next(result);
observer.complete();
};
if (term) {
let service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: term }, displaySuggestions);
}
});
}
}
答案 0 :(得分:1)
不知道你是否仍然感兴趣,但今天我在使用bootstrap typeahead遇到同样的问题。我想我找到了一个解决方案,虽然我不认为这是应该这样做的方式。 无论如何,我的方法是收集数据并让数据显示为静态数据。
ngOnInit(): void {
//this.recursiveTimeout();
this.items = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((term: string) => this.placesService.search(term))
.catch(() => {
this.searchFailed = true;
return Observable.of([])
}
)
this.items.subscribe(res => {
this.places = res;
//places is a string array and stores all found places , in your case it
would be an array of GooglePlace
console.log(this.places);
});
}
然后,您可以在数据可用时尽快访问。
答案 1 :(得分:1)
我与谷歌地图有一个非常相似的问题。我会在这里分享我的答案,尽管已经很晚了。
问题是因为google地图getQueryPredictions的回调函数displaySuggestions在'angular zone'之外调用,因此angular无法正确检测其内部的变化。
解决方案相对简单。只需对app / google.service.ts进行4次小修改即可。见评论。
// import NgZone
import { Injectable, NgZone } from '@angular/core';
import { GooglePlace } from './google-place';
import { Observable } from 'rxjs/Observable';
declare var google: any;
@Injectable()
export class GoogleService {
// Inject NgZone in the constructor
constructor(private _ngZone: NgZone) {}
search(term: string) {
// save 'this' to a constant or alternatively bind it to the callback function
const self = this;
return new Observable<GooglePlace[]>(observer => {
const result: GooglePlace[] = [];
const displaySuggestions = function(predictions: any, status: string) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
console.log('GoogleService search: ', status);
return;
}
// Wrap the prediction in the zone
self._ngZone.run(function() {
predictions.forEach(function(prediction: any) {
result.push(
new GooglePlace(prediction.place_id, prediction.description)
);
});
observer.next(result);
observer.complete();
});
};
if (term) {
const service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: term }, displaySuggestions);
}
});
}
}
编辑:也许你应该从plunker中取出你的API密钥,虽然我认为它可能不是一个严重的问题,如果它是一个免费的,并且是专门为了示例的目的而创建的...
答案 2 :(得分:0)
我找到了一个糟糕的解决方案。在 app / google-search.component.ts 中,我添加了以下功能:
recursiveTimeout(ms: number = 1000): void {
setTimeout(() => {
this.recursiveTimeout(ms);
}, ms);
}
然后在ngOnInit
函数中,我调用recursiveTimeout
:
ngOnInit(): void {
this.recursiveTimeout();
// ...
}
使用此解决方案,当用户键入“P”(例如):
recursiveTimeout
被触发后显示(最长1000毫秒)我愿意接受任何更好的解决方案;)