Google Maps Places Autocomplete - Uncaught TypeError: Cannot read property 'getPlace' of undefined
Google Maps Places Autocomplete - Uncaught TypeError: Cannot read property 'getPlace' of undefined
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>
我有这些函数,这些函数应该从 Google 地图位置从输入字段(originInput 和 destinationPlaceInput)给我方向 A 到 B。
在我 select 输入后,我在控制台中出现此错误:
Uncaught TypeError: Cannot read property 'getPlace' of undefined
此错误在 "place_changed" 事件触发后抛出。
在 place_changed
-回调中,关键字 this
指向已触发事件的对象。
所以你可以简单地使用
var place = this.getPlace();
而不是
var place = this.destinationAutocomplete.getPlace();
如何保持控制器的上下文/this
?
tldr:
创建一个函数,returns一个具有上下文的函数:
this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));
说明
如Dr.Molle指出:this
指向触发事件的对象,即要添加事件监听器的元素。
addListener 采用函数声明。要继续访问控制器的 this
,您还可以创建一个闭包,将控制器的 this
传递到函数中,如下所示:
this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));
我在这里定义了一个函数,它接受一个名为 that
的参数,并且在执行时 returns 一个包含 this 的函数。它是一个闭包,因为内部函数的范围保留了对来自外部函数范围的 that
变量的引用(以及可以传递给 this.placesChanged
的其他变量)。
现在,如果发出事件 places_changed
,则函数声明为 运行。我仍然能够在 this.placesChanged
函数内更改 that
变量的属性。这是可能的,因为 in 对象是通过引用传递的(而原始类型是通过值传递的)。
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>
我有这些函数,这些函数应该从 Google 地图位置从输入字段(originInput 和 destinationPlaceInput)给我方向 A 到 B。
在我 select 输入后,我在控制台中出现此错误:
Uncaught TypeError: Cannot read property 'getPlace' of undefined
此错误在 "place_changed" 事件触发后抛出。
在 place_changed
-回调中,关键字 this
指向已触发事件的对象。
所以你可以简单地使用
var place = this.getPlace();
而不是
var place = this.destinationAutocomplete.getPlace();
如何保持控制器的上下文/this
?
tldr:
创建一个函数,returns一个具有上下文的函数:
this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));
说明
如Dr.Molle指出:this
指向触发事件的对象,即要添加事件监听器的元素。
addListener 采用函数声明。要继续访问控制器的 this
,您还可以创建一个闭包,将控制器的 this
传递到函数中,如下所示:
this.searchBox.addListener('places_changed', ((that) => () => this.placesChanged(that))(this));
我在这里定义了一个函数,它接受一个名为 that
的参数,并且在执行时 returns 一个包含 this 的函数。它是一个闭包,因为内部函数的范围保留了对来自外部函数范围的 that
变量的引用(以及可以传递给 this.placesChanged
的其他变量)。
现在,如果发出事件 places_changed
,则函数声明为 运行。我仍然能够在 this.placesChanged
函数内更改 that
变量的属性。这是可能的,因为 in 对象是通过引用传递的(而原始类型是通过值传递的)。