gpt4 book ai didi

javascript - 触发 infoWindow 单击 - 未捕获的 TypeError : Cannot read property '__e3_' of undefined

转载 作者:行者123 更新时间:2023-12-03 10:35:21 28 4
gpt4 key购买 nike

注意:我已经阅读了 StackOverflow 上的五篇帖子,其中已经出现了相同的错误,但它们没有解决我的问题。

我正在开发一个类(class)项目,它是一个单页 JavaScript 应用程序,它使用 Google map JavaScript API 向用户显示所在城市的健身房。我已经开始进行搜索了。我已经让信息窗口正常工作(单击 map 上的标记将弹出一个信息窗口,其中包含有关特定健身房的相关详细信息),但现在我试图让应用程序在用户单击时打开指定的信息窗口 ListView 中的健身房名称。我正在查看 Google 的示例来构建我的应用程序。具体来说,我正在尝试模拟 this one 的功能。

一旦用户单击列表中的健身房名称,错误就会显示在控制台中。我相信导致它的代码行在我的 buildListView() 函数中(大约是下面文件高度的 70%)。我已在该函数中可疑行的右侧添加了注释。

继续吧play with it yourself看看我的意思。任何帮助将不胜感激:)

<!DOCTYPE html>
<html>
<head>
<title>Place searches</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
#pac-input {
width: 350px;
height: 25px;
font-size: 16px;
margin: 10px;
padding: 5px
}
ul {
z-index: 2; /* Fixes infoWindow and list view overlap issue */
}
li:hover {
background: gray;
color: white;
}
table {
font-size: 12px;
}
.placeIcon {
width: 20px;
height: 34px;
margin: 4px;
}
.hotelIcon {
width: 24px;
height: 24px;
}
#rating {
font-size: 13px;
font-family: Arial Unicode MS;
}
.iw_table_row {
height: 18px;
}
.iw_attribute_name {
font-weight: bold;
text-align: right;
}
.iw_table_icon {
text-align: right;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places"></script>
<script>
var madison,
map,
infoWindow,
autocomplete,
service,
controlList,
messageDiv;

var anyInfoWindowSeenAlready = false;

var markers = [],
gyms = [];

var hostnameRegexp = new RegExp('^https?://.+?/');

function initialize() {
madison = new google.maps.LatLng(43.0667, -89.4000),
mapOptions = {
center: madison,
zoom: 12,
streetViewControl: false,
mapTypeControl: false
},
autocompleteOptions = {
types: ['(cities)']
};

map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

infoWindow = new google.maps.InfoWindow({
content: document.getElementById('info-content')
});

document.getElementById('info-content').style.display = 'none';

var input = document.getElementById('pac-input');
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

// Create the DIV to hold the control and call the
// ListControl() constructor passing in this DIV.
var listControlDiv = document.createElement('div');
var listControl = new ListControl(listControlDiv, map);
map.controls[google.maps.ControlPosition.LEFT_TOP].push(listControlDiv);

// Create the 'Find a gym near you!' message div and
// push it onto the map canvas as a map control
messageDiv = document.createElement('div');
messageDiv = buildMessageDiv(messageDiv);
map.controls[google.maps.ControlPosition.TOP_CENTER].push(messageDiv);

autocomplete = new google.maps.places.Autocomplete(input, autocompleteOptions);
service = new google.maps.places.PlacesService(map);

var request = {
location: madison,
radius: 25000,
types: ['gym']
};
service.nearbySearch(request, callback);
google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged);
}

/**
* The ListControl adds a control to the map that
* displays the search results in a list view. This
* constructor takes the control DIV as an argument.
*/
function ListControl(controlDiv, map) {

var madison = new google.maps.LatLng(43.0667, -89.4000);

// Set CSS styles for the DIV containing the control
// Setting padding to 5 px will offset the control
// from the edge of the map.
controlDiv.style.padding = '10px';
controlDiv.style.opacity = '0.6';

// Set CSS for the control border.
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = 'white';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderWidth = '1px';
controlUI.style.textAlign = 'center';
controlUI.title = 'List of gyms returned by search';
controlDiv.appendChild(controlUI);

// Set CSS for the control interior.
controlList = document.createElement('ul');
controlList.style.listStyleType = 'none';
controlList.style.maxHeight = '500px';
controlList.style.maxWidth = '300px';
controlList.style.overflowY = 'auto';
controlList.style.overflowX = 'hidden';
controlList.style.fontFamily = 'Arial,sans-serif';
controlList.style.fontSize = '16px';
controlList.style.padding = '0px';
controlList.style.margin = '0px';
controlUI.appendChild(controlList);

// Setup the click event listeners
// google.maps.event.addDomListener(controlUI, 'click', function() {
// map.setCenter(madison)
// });
}

// When the user selects a city, perform a nearbySearch()
// for gyms in that city
function onPlaceChanged() {
var place = autocomplete.getPlace();
if (place.geometry) {
clearMarkers();
map.panTo(place.geometry.location);
map.setZoom(12);
var request = {
location: place.geometry.location,
radius: 25000,
types: ['gym']
};
service.nearbySearch(request, callback);
messageDiv.style.fontSize = '14px';
messageDiv.innerHTML = '<h1>Here are the top 20 gyms in your city. Click to see details.</h1>';
} else {
document.getElementById('pac-input').placeholder = 'Start typing city name, then select a city from list';
}
}

function buildMessageDiv(messageDiv) {
messageDiv.innerHTML = '<h1>Find a gym near you!</h1>';
messageDiv.style.textAlign = 'center';
messageDiv.style.fontSize = '20px';
messageDiv.style.visibility = 'visible';
return messageDiv;

}


function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
gyms = results;
for (var i = 0; i < gyms.length; i++) {
markers[i] = createMarker(gyms[i]);
markers[i].placeResult = gyms[i];
}
}
buildListView();
}

function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: placeLoc
});

google.maps.event.addListener(marker, 'click', showInfoWindow);

return marker;
}

function clearMarkers() {
for (var i = 0; i < markers.length; i++) {
if (markers[i]) {
markers[i].setMap(null);
}
}
markers = [];
}

function buildListView() {
controlList.innerHTML = '';
for (var i = 0; i < gyms.length; i++) {
if (gyms[i]) {
var li = document.createElement('li');
li.onclick = function() {
google.maps.event.trigger(markers[i], 'click'); //<<--This line!
};
li.innerHTML = gyms[i].name;
li.style.padding = '15px';
li.style.cursor = 'pointer';
li.setAttribute("id", gyms[i].name);
controlList.appendChild(li);
}
}
}

// Get the place details for a hotel. Show the information in an info window,
// anchored on the marker for the hotel that the user selected.
function showInfoWindow() {
var marker = this;
service.getDetails({placeId: marker.placeResult.place_id},
function(place, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
return;
}
if (anyInfoWindowSeenAlready === false) {
document.getElementById('info-content').style.display = 'initial';
}
infoWindow.open(map, marker);
buildIWContent(place);
anyInfoWindowSeenAlready = true;
});
}

// Load the place information into the HTML elements used by the info window.
function buildIWContent(place) {
document.getElementById('iw-icon').innerHTML = '<img class="hotelIcon" ' +
'src="' + place.icon + '"/>';
document.getElementById('iw-url').innerHTML = '<b><a href="' + place.url +
'">' + place.name + '</a></b>';
document.getElementById('iw-address').textContent = place.vicinity;

if (place.formatted_phone_number) {
document.getElementById('iw-phone-row').style.display = '';
document.getElementById('iw-phone').textContent =
place.formatted_phone_number;
} else {
document.getElementById('iw-phone-row').style.display = 'none';
}

// Assign a five-star rating to the hotel, using a black star ('&#10029;')
// to indicate the rating the hotel has earned, and a white star ('&#10025;')
// for the rating points not achieved.
if (place.rating) {
var ratingHtml = '';
for (var i = 0; i < 5; i++) {
if (place.rating < (i + 0.5)) {
ratingHtml += '&#10025;';
} else {
ratingHtml += '&#10029;';
}
document.getElementById('iw-rating-row').style.display = '';
document.getElementById('iw-rating').innerHTML = ratingHtml;
}
} else {
document.getElementById('iw-rating-row').style.display = 'none';
}

// The regexp isolates the first part of the URL (domain plus subdomain)
// to give a short URL for displaying in the info window.
if (place.website) {
var fullUrl = place.website;
var website = hostnameRegexp.exec(place.website);
if (website == null) {
website = 'http://' + place.website + '/';
fullUrl = website;
}
document.getElementById('iw-website-row').style.display = '';
document.getElementById('iw-website').textContent = website;
} else {
document.getElementById('iw-website-row').style.display = 'none';
}
}

google.maps.event.addDomListener(window, 'load', initialize);

</script>
</head>
<body>

<input id="pac-input" class="controls" type="text"
placeholder="Start typing city name, then select a city from list">

<div id="map-canvas"></div>

<div id="info-content">
<table>
<tr id="iw-url-row" class="iw_table_row">
<td id="iw-icon" class="iw_table_icon"></td>
<td id="iw-url"></td>
</tr>
<tr id="iw-address-row" class="iw_table_row">
<td class="iw_attribute_name">Address:</td>
<td id="iw-address"></td>
</tr>
<tr id="iw-phone-row" class="iw_table_row">
<td class="iw_attribute_name">Telephone:</td>
<td id="iw-phone"></td>
</tr>
<tr id="iw-rating-row" class="iw_table_row">
<td class="iw_attribute_name">Rating:</td>
<td id="iw-rating"></td>
</tr>
<tr id="iw-website-row" class="iw_table_row">
<td class="iw_attribute_name">Website:</td>
<td id="iw-website"></td>
</tr>
</table>
</div>

</body>
</html>

最佳答案

这是在循环中定义对标记的引用时的常见问题。解决这个问题的一种方法是使用函数闭包(一个对其参数保持闭包的函数):

function buildListView() {
controlList.innerHTML = '';
for (var i = 0; i < gyms.length; i++) {
if (gyms[i]) {
clickableLink(i);
}
}
}

function clickableLink(i) {
var li = document.createElement('li');
li.onclick = function () {
google.maps.event.trigger(markers[i], 'click'); //<<--This line!
};
li.innerHTML = gyms[i].name;
li.style.padding = '15px';
li.style.cursor = 'pointer';
li.setAttribute("id", gyms[i].name);
controlList.appendChild(li);

}

更多关于Function closure

工作代码片段:

var madison,
map,
infoWindow,
autocomplete,
service,
controlList,
messageDiv;

var anyInfoWindowSeenAlready = false;

var markers = [],
gyms = [];

var hostnameRegexp = new RegExp('^https?://.+?/');

function initialize() {
madison = new google.maps.LatLng(43.0667, -89.4000),
mapOptions = {
center: madison,
zoom: 12,
streetViewControl: false,
mapTypeControl: false
},
autocompleteOptions = {
types: ['(cities)']
};

map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

infoWindow = new google.maps.InfoWindow({
content: document.getElementById('info-content')
});

document.getElementById('info-content').style.display = 'none';

var input = document.getElementById('pac-input');
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

// Create the DIV to hold the control and call the
// ListControl() constructor passing in this DIV.
var listControlDiv = document.createElement('div');
var listControl = new ListControl(listControlDiv, map);
map.controls[google.maps.ControlPosition.LEFT_TOP].push(listControlDiv);

// Create the 'Find a gym near you!' message div and
// push it onto the map canvas as a map control
messageDiv = document.createElement('div');
messageDiv = buildMessageDiv(messageDiv);
map.controls[google.maps.ControlPosition.TOP_CENTER].push(messageDiv);

autocomplete = new google.maps.places.Autocomplete(input, autocompleteOptions);
service = new google.maps.places.PlacesService(map);

var request = {
location: madison,
radius: 25000,
types: ['gym']
};
service.nearbySearch(request, callback);
google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged);
}

/**
* The ListControl adds a control to the map that
* displays the search results in a list view. This
* constructor takes the control DIV as an argument.
*/
function ListControl(controlDiv, map) {

var madison = new google.maps.LatLng(43.0667, -89.4000);

// Set CSS styles for the DIV containing the control
// Setting padding to 5 px will offset the control
// from the edge of the map.
controlDiv.style.padding = '10px';
controlDiv.style.opacity = '0.6';

// Set CSS for the control border.
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = 'white';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderWidth = '1px';
controlUI.style.textAlign = 'center';
controlUI.title = 'List of gyms returned by search';
controlDiv.appendChild(controlUI);

// Set CSS for the control interior.
controlList = document.createElement('ul');
controlList.style.listStyleType = 'none';
controlList.style.maxHeight = '500px';
controlList.style.maxWidth = '300px';
controlList.style.overflowY = 'auto';
controlList.style.overflowX = 'hidden';
controlList.style.fontFamily = 'Arial,sans-serif';
controlList.style.fontSize = '16px';
controlList.style.padding = '0px';
controlList.style.margin = '0px';
controlUI.appendChild(controlList);

// Setup the click event listeners
// google.maps.event.addDomListener(controlUI, 'click', function() {
// map.setCenter(madison)
// });
}

// When the user selects a city, perform a nearbySearch()
// for gyms in that city
function onPlaceChanged() {
var place = autocomplete.getPlace();
if (place.geometry) {
clearMarkers();
map.panTo(place.geometry.location);
map.setZoom(12);
var request = {
location: place.geometry.location,
radius: 25000,
types: ['gym']
};
service.nearbySearch(request, callback);
messageDiv.style.fontSize = '14px';
messageDiv.innerHTML = '<h1>Here are the top 20 gyms in your city. Click to see details.</h1>';
} else {
document.getElementById('pac-input').placeholder = 'Start typing city name, then select a city from list';
}
}

function buildMessageDiv(messageDiv) {
messageDiv.innerHTML = '<h1>Find a gym near you!</h1>';
messageDiv.style.textAlign = 'center';
messageDiv.style.fontSize = '20px';
messageDiv.style.visibility = 'visible';
return messageDiv;

}


function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
gyms = results;
for (var i = 0; i < gyms.length; i++) {
markers[i] = createMarker(gyms[i]);
markers[i].placeResult = gyms[i];
}
}
buildListView();
}

function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: placeLoc
});

google.maps.event.addListener(marker, 'click', showInfoWindow);

return marker;
}

function clearMarkers() {
for (var i = 0; i < markers.length; i++) {
if (markers[i]) {
markers[i].setMap(null);
}
}
markers = [];
}

function buildListView() {
controlList.innerHTML = '';
for (var i = 0; i < gyms.length; i++) {
if (gyms[i]) {
clickableLink(i);
}
}
}

function clickableLink(i) {
var li = document.createElement('li');
li.onclick = function() {
google.maps.event.trigger(markers[i], 'click'); //<<--This line!
};
li.innerHTML = gyms[i].name;
li.style.padding = '15px';
li.style.cursor = 'pointer';
li.setAttribute("id", gyms[i].name);
controlList.appendChild(li);

}

// Get the place details for a hotel. Show the information in an info window,
// anchored on the marker for the hotel that the user selected.
function showInfoWindow() {
var marker = this;
service.getDetails({
placeId: marker.placeResult.place_id
},

function(place, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
return;
}
if (anyInfoWindowSeenAlready === false) {
document.getElementById('info-content').style.display = 'initial';
}
infoWindow.open(map, marker);
buildIWContent(place);
anyInfoWindowSeenAlready = true;
});
}

// Load the place information into the HTML elements used by the info window.
function buildIWContent(place) {
document.getElementById('iw-icon').innerHTML = '<img class="hotelIcon" ' +
'src="' + place.icon + '"/>';
document.getElementById('iw-url').innerHTML = '<b><a href="' + place.url +
'">' + place.name + '</a></b>';
document.getElementById('iw-address').textContent = place.vicinity;

if (place.formatted_phone_number) {
document.getElementById('iw-phone-row').style.display = '';
document.getElementById('iw-phone').textContent = place.formatted_phone_number;
} else {
document.getElementById('iw-phone-row').style.display = 'none';
}

// Assign a five-star rating to the hotel, using a black star ('&#10029;')
// to indicate the rating the hotel has earned, and a white star ('&#10025;')
// for the rating points not achieved.
if (place.rating) {
var ratingHtml = '';
for (var i = 0; i < 5; i++) {
if (place.rating < (i + 0.5)) {
ratingHtml += '&#10025;';
} else {
ratingHtml += '&#10029;';
}
document.getElementById('iw-rating-row').style.display = '';
document.getElementById('iw-rating').innerHTML = ratingHtml;
}
} else {
document.getElementById('iw-rating-row').style.display = 'none';
}

// The regexp isolates the first part of the URL (domain plus subdomain)
// to give a short URL for displaying in the info window.
if (place.website) {
var fullUrl = place.website;
var website = hostnameRegexp.exec(place.website);
if (website == null) {
website = 'http://' + place.website + '/';
fullUrl = website;
}
document.getElementById('iw-website-row').style.display = '';
document.getElementById('iw-website').textContent = website;
} else {
document.getElementById('iw-website-row').style.display = 'none';
}
}

google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
#pac-input {
width: 350px;
height: 25px;
font-size: 16px;
margin: 10px;
padding: 5px
}
ul {
z-index: 2;
/* Fixes infoWindow and list view overlap issue */
}
li:hover {
background: gray;
color: white;
}
table {
font-size: 12px;
}
.placeIcon {
width: 20px;
height: 34px;
margin: 4px;
}
.hotelIcon {
width: 24px;
height: 24px;
}
#rating {
font-size: 13px;
font-family: Arial Unicode MS;
}
.iw_table_row {
height: 18px;
}
.iw_attribute_name {
font-weight: bold;
text-align: right;
}
.iw_table_icon {
text-align: right;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>

<input id="pac-input" class="controls" type="text" placeholder="Start typing city name, then select a city from list">
<div id="map-canvas"></div>
<div id="info-content">
<table>
<tr id="iw-url-row" class="iw_table_row">
<td id="iw-icon" class="iw_table_icon"></td>
<td id="iw-url"></td>
</tr>
<tr id="iw-address-row" class="iw_table_row">
<td class="iw_attribute_name">Address:</td>
<td id="iw-address"></td>
</tr>
<tr id="iw-phone-row" class="iw_table_row">
<td class="iw_attribute_name">Telephone:</td>
<td id="iw-phone"></td>
</tr>
<tr id="iw-rating-row" class="iw_table_row">
<td class="iw_attribute_name">Rating:</td>
<td id="iw-rating"></td>
</tr>
<tr id="iw-website-row" class="iw_table_row">
<td class="iw_attribute_name">Website:</td>
<td id="iw-website"></td>
</tr>
</table>
</div>

关于javascript - 触发 infoWindow 单击 - 未捕获的 TypeError : Cannot read property '__e3_' of undefined,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29014640/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com