Google Maps Places Autocomplete - Uncaught TypeErr

2019-07-31 23:35发布

setAutocomplete() {
    this.originPlaceId = null;
    this.destinationPlaceId = null;
    this.travelMode = google.maps.TravelMode.WALKING;
    this.directionsDisplay.setMap(this.map);

    this.setMapControls(this.map);

    this.setupClickListener('changemode-walking', google.maps.TravelMode.WALKING);
    this.setupClickListener('changemode-transit', google.maps.TravelMode.TRANSIT);
    this.setupClickListener('changemode-driving', google.maps.TravelMode.DRIVING);

    console.log(this.originInput);
    this.originAutocomplete = new google.maps.places.Autocomplete(this.originInput);
    this.originAutocomplete.bindTo('bounds', this.map);
    console.log(this.originAutocomplete);
    this.originAutocomplete.addListener('place_changed', function() {
        console.log(this.originAutocomplete);
        var place = this.originAutocomplete.getPlace();
        console.log("here", place);
        if (!place.geometry) {
            window.alert("Autocomplete's returned place contains no geometry");
            return;
        }
        this.expandViewportToFitPlace(this.map, place);

        // If the place has a geometry, store its place ID and route if we have
        // the other place ID
        this.originPlaceId = place.place_id;
        this.route(this.directionsService, this.directionsDisplay);
    });

    this.destinationAutocomplete = new google.maps.places.Autocomplete(this.destinationPlaceInput);
    this.destinationAutocomplete.bindTo('bounds',this.map);
    this.destinationAutocomplete.addListener('place_changed', function() {
        var place = this.destinationAutocomplete.getPlace();
        if (!place.geometry) {
            window.alert("Autocomplete's returned place contains no geometry");
            return;
        }
        this.expandViewportToFitPlace(this.map, place);

        // If the place has a geometry, store its place ID and route if we have
        // the other place ID
        this.destinationPlaceId = place.place_id;
        this.route(this.directionsService, this.directionsDisplay);
        //this.getNearbyPlaces(this.destinationPlaceId, 5000);
    });
};
setMapControls(map) {
    this.originInput = document.getElementById('origin-input');
    this.destinationPlaceInput = document.getElementById('destination-input');
    this.modes = document.getElementById('mode-selector');

    map.controls[google.maps.ControlPosition.TOP_LEFT].push(this.originInput);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(this.destinationPlaceInput);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(this.modes);
};
<input id="origin-input" class="controls" type="text" force-selection="true" placeholder="Enter an origin location">
<input id="destination-input" class="controls" type="text" force-selection="true" placeholder="Enter a destination location">
<div id="mode-selector" class="controls">
    <input type="radio" name="type" id="changemode-walking" checked="checked">
    <label for="changemode-walking">Walking</label>
    <input type="radio" name="type" id="changemode-transit">
    <label for="changemode-transit">Transit</label>
    <input type="radio" name="type" id="changemode-driving">
    <label for="changemode-driving">Driving</label>
</div>
<div id="directionsList"></div>
<div id="map_canvas"></div>

I have these functions which are supposed to give me the directions A to B from Google Maps Places from the input fields (originInput and destinationPlaceInput).

After I select an input I have this error in console:

Uncaught TypeError: Cannot read property 'getPlace' of undefined

This error is thrown after the "place_changed" event triggers.

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-07-31 23:59

How to keep the context/this of the controller?

tldr:

Create a function that returns a function with the context:

this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));

Explanation

Like Dr.Molle points out: this points to the object which has triggered the event, namely the element on which you want to add an event listener on.

The addListener takes a function declaration. To keep access on your controller's this, you could also create a closure that passes the controller's this into the function, like so:

this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));

Here I defined a function that takes a parameter called that, and upon execution returns a function that contains the this. It is a closure because the inner function's scope keeps a reference to the that variable from the outer functions scope (and other variables that could get passed to this.placesChanged).

Now if a event places_changed is emitted, the function declaration is ran. I am still able to change properties on the that variable inside the this.placesChanged function. This is possible because in objects are passed by reference (whereas primitive types are passed by values).

查看更多
Animai°情兽
3楼-- · 2019-08-01 00:14

Inside the place_changed-callback the keyword this points to the object which has been triggered the event.

so you may simply use

var place = this.getPlace();

instead of

var place = this.destinationAutocomplete.getPlace();
查看更多
登录 后发表回答