Reputation: 37
I try to consume an observable through an async pipe, here is my template :
<input #address type="text" id="address" placeholder="{{placeHolder}}" (keyup)="addTerm(address.value)" />
<div *ngFor="let place of possiblesPlaces | async">
{{place.label}}
</div>
Here is the component part :
export class LocationFieldComponent implements OnInit{
private searchTerms = new Subject<string>();
@Input()
placeHolder:string;
possiblesPlaces:Observable<Array<{label:string,value:any}>>;
addTerm(address:string) {
this.searchTerms.next(address);
}
ngOnInit(): void {
this.possiblesPlaces=this.searchTerms.filter(t=>t.length>2).debounceTime(300).distinctUntilChanged()
.flatMap(term =>
Observable.of(this.fetchResults(term))
)
.catch(error => {
// TODO: real error handling
console.log(error);
return Observable.of([]);
});
this.possiblesPlaces.subscribe(val => console.log(val))
}
fetchResults(address:string) :Array<{label:string,value:any}> {
var result=new Array;
var geocoder = new google.maps.Geocoder();
console.log("search with"+address);
geocoder.geocode( { 'address': address}, (results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
for(let i=0;i<results.length;i++){
result.push( {label:results[i].formatted_address,value:null});
}
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
return result;
}
}
I can see all the new values of the possiblesPlaces oberservable on the console but the async pipe won't show any results.
Sometimes i can see the results of the previous observable value for half a second when typing a new letter in the address field, i don't understand why?
EDIT: i discovered if i wait like 20 seconds, the results appear correctly. The request to the google api is quick but the async pipe seems to take a while. Any ides?
Upvotes: 1
Views: 1779
Reputation: 657937
This should work
fetchResults(address:string) :Array<{label:string,value:any}> {
var subj = new Subject();
var geocoder = new google.maps.Geocoder();
console.log("search with"+address);
geocoder.geocode( { 'address': address}, (results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
for(let i=0;i<results.length;i++){
subject.next( {label:results[i].formatted_address,value:null});
}
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
return subj.asObservable();
}
ngOnInit(): void {
this.possiblesPlaces=this.searchTerms.filter(t=>t.length>2).debounceTime(300).distinctUntilChanged()
.flatMap(term =>
this.fetchResults(term).scan([], acc, x) => acc.concat(x));
)
.catch(error => {
// TODO: real error handling
console.log(error);
return Observable.of([]);
});
this.possiblesPlaces.map(val => console.log(val))
}
fetchResults()
returns an observable. In your question you return an empty array and then only fill it later when the response from Geocoder arrives. That doesn't look too reliable.
ngOnInit()
uses this.possiblePlaces.subscribe()
but subscribe
returns a Subscription
not an Observable
and | async
only works with Promise
and Observable
but not with Subscription
. If you use map
instead of subscribe
an Observable
is returned.
Upvotes: 2
Reputation: 37
Ok i figured out!
You can"t use http request like geocoder.geocode which use a callback function, you have to deal with the angular way using http.get with an url
Upvotes: 0