user2343946
user2343946

Reputation: 37

Angular2 async pipe with observable

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

Answers (2)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

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

user2343946
user2343946

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

Related Questions