javascript - 过滤标记并使用 knockout 和谷歌地图列出 - 未捕获的类型错误无法读取未定义的属性 'marker'

标签 javascript html google-maps knockout.js

我希望能够单击标记城市名称并弹出该特定<的info.window em>标记

HTML:

    <!DOCTYPE html>
<html>
  <head>
      <title>Magic Towns of Mexico</title>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <link rel="stylesheet" href="css/styles.css">
    <style>
      html,
      body {
        font-family: Arial, sans-serif;
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #map {
        height: 100%;
      }
    </style>
  </head>
  <body>

<div id="map"></div>
<div class="menuContainer">
  <span class="center" style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776;</span>
  <div id="mySidenav" class="sidenav alignTextCenter">
    <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
    <a href="#"><h1>Locations:</h1></a>
    <form role="search">
                    <input type="text" data-bind="value: query, valueUpdate: 'keyup'" placeholder="Search...">
    </form>
    <div data-bind='with: currentPlace' >
      <div data-bind='foreach: filteredPlaces' class="alignTextCenter">
        <p href="#" class="whiteFont" data-bind='text: city, click: clickSelection'></p>
      </div>
    </div>
  </div>
</div>

    <script src='js/sidebar.js'></script>
    <script src="js/jquery-3.2.1.min.js"></script>
    <script src="js/knockout-3.4.2.js"></script>
    <script src="js/data.js"></script>
    <script src="js/app2.js"></script>
    <script async defer
        src="https://maps.googleapis.com/maps/api/js?libraries=geometrykey=AIzaSyBnwbuI0b5q6p5sJAa2wcHIy2DGkZFisBY&v=3&callback=initMap">
    </script>

  </body>
</html>

JavaScript:

var initialPlaces = [
  {"city":"Tepotzotlán","lat":19.7185096,"lng":-99.2065202},
  {"city":"Valle de Bravo","lat":19.1950964,"lng":-100.1326725},
  {"city":"Cuitzeo","lat":19.9685057,"lng":-101.1406046},
  {"city":"Pátzcuaro","lat":19.5134498,"lng":-101.6091554},
  {"city":"Sta. Clara del Cobre","lat":19.4064279,"lng":-101.639697899999},
];

var map, google;
var markers = [];
var wikiElem;

var Place = function(data) {
    this.city = ko.observable(data.city);
    this.lat = ko.observable(data.lat);
    this.lng = ko.observable(data.lng);
};

var ViewModel = function() {
    var self = this;

    self.placeList = ko.observableArray([]);
    self.query = ko.observable(''),

    initialPlaces.forEach(function(placeLocation) {
      self.placeList.push( new Place(placeLocation));
    });
    self.currentPlace = ko.observable( this.placeList()[0]);

    // Populate infowindow
    this.populateInfoWindow = function(marker, infoWindow) {
      if (infoWindow.marker != marker) {
        infoWindow.marker = marker;
        var $wikiElem = '';
        var cityStr = marker.city;
        var wikiUrl = 'http://en.wikipedia.org/w/api.php?action=opensearch&search=' +
          cityStr + '&format=json&callback=wikiCallback';
        var wikiRequestTimeOut = setTimeout(function() {
          $wikiElem = 'failed to get wikipedia resources';
        }, 8000);

        $.ajax({
          url: wikiUrl,
          dataType: "jsonp",
          success: function(response) {
            var articleList = response[1];
            for (var i = 0; i < articleList.length; i++) {
              articleStr = articleList[i];
              var url = 'http://en.wikipedia.org/wiki/' + articleStr;
              $wikiElem += '<li><a href="' + url + '">' + articleStr + '</a></li>';
            }
            infoWindow.setContent(self.titleContent + '<hr>' + self.wikiTitle + $wikiElem);
            clearTimeout(wikiRequestTimeOut);
          }
        });
        self.wikiTitle = '<h3>Relevant Wikipedia Links</h3>';
        self.titleContent = '<div>' + marker.city + '<div>';
        infoWindow.open(map, marker);

        marker.setAnimation(google.maps.Animation.BOUNCE);
        setTimeout(function () {
          marker.setAnimation(null);
        }, 1500 );
        // Cleared infowindow if is closed
        infoWindow.addListener('closeclick', function() {
          infoWindow.marker = null;
        });
      }
    };

    // Handles click selection on map and list
    self.clickSelection = function() {
      self.populateInfoWindow(this, self.largeInfoWindow);
    };

    // Construct Map
    self.initMap = function() {
      map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 24.3001235, lng: -102.2718002},
        zoom: 5,
      });

      var largeInfoWindow = new google.maps.InfoWindow();
      // Create array for markers
      for (var i = 0; i < initialPlaces.length; i++) {
        this.city = initialPlaces[i].city;
        this.lat = initialPlaces[i].lat;
        this.lng = initialPlaces[i].lng;
        // create a marker per city
        this.marker = new google.maps.Marker({
          map: map,
          position: {lat: this.lat, lng: this.lng},
          city: this.city,
          icon: {
                path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
                scale: 5
              },
          animation: google.maps.Animation.DROP,
        });
        // Push the marker to our array of markers.
        this.markers.push(this.marker);
        this.marker.addListener('click', self.clickSelection);
      }

    };

    self.filteredPlaces = ko.computed(function() {
      if (!self.query()) {
        return self.placeList();
      } else {
        return self.placeList()
          .filter(place => place.city().toLowerCase().indexOf(self.query().toLowerCase()) > -1);
      }
    });

};



    ko.applyBindings(ViewModel);

我希望能够单击标记来填充 info.window,如果我单击要填充 info.window 的列表,我也希望能够单击该标记>.

我现在得到的结果是这个错误:

Uncaught TypeError: Cannot read property 'marker' of undefined at ViewModel.populateInfoWindow (app2.js:24)

最佳答案

此代码存在多个问题。

  1. 首先,对 google map api 的脚本引用有错误。它应该有 &key 而不是 geometrykey & 是因为它们是单独的参数。

    https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyBnwbuI0b5q6p5sJAa2wcHIy2DGkZFisBY&v=3&callback=initMap

  2. 接下来,您的回调函数不存在。所以我创建了它。

    function initMap() {
     var viewmodel = new ViewModel();
     viewmodel.initMap();
    }
    
  3. initMap 方法中的这一行需要更改: var largeInfoWindow = new google.maps.InfoWindow();

    在 JavaScript 中使用 var 创建一个新的局部变量。 largeInfoWindow 是 initMap 范围内的局部变量。为了使其在该范围之外可见,请将其替换为 this。

    self.largeInfoWindow = new google.maps.InfoWindow();
    
  4. 如果您通过 http://访问您的网站,我将您的 http://wikipedia api 调用更改为 https://。但是,如果您通过 http 访问您的网站,则可以不理会它。

将来使用 jsFiddle(或类似的东西,如 codepen 或 Pastebin)可能会更容易。

关于javascript - 过滤标记并使用 knockout 和谷歌地图列出 - 未捕获的类型错误无法读取未定义的属性 'marker',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47758158/

相关文章:

javascript - Visual Studio/ASP.NET MVC 项目上的 JSLint

html - 字体不适用于 Windows 版本的浏览器

javascript - 使用 jQuery 从 json 动态呈现无序列表

google-maps - 谷歌地图 - 在边界/视口(viewport)内搜索

android - Keytool 命令出错

javascript - 当用户选择页面上的某些文本时触发的事件是什么?

javascript - Vue风格没有被应用

javascript - JavaScript 是否支持偏函数应用?

html - 如何在限制 <a> 元素的可点击区域的同时将 <a> 元素置于 <div> 元素的中心?

javascript - 谷歌API反向地理编码