如何使用knockout.js将复选框绑定到谷歌地图标记

How to bind checkboxes to Google Maps markers using knockout.js?

本文关键字:谷歌 地图 图标 绑定 复选框 何使用 knockout js      更新时间:2023-09-26

我正在创建一个应用程序,它可以呈现一个城市的谷歌地图,并带有附近位置的位置标记。我通过向google.maps.places.PlacesService API请求800单位半径内的位置来呈现这些位置。此外,我有许多复选框表示地点类型(例如公园、博物馆等)。当选中或未选中这些框时,我希望地图能够动态更新并显示或隐藏相应的地图标记。我正在使用knockout.js框架来帮助实现。

我的复选框是knockout observable,我已经设法创建了一个在html中动态变化的复选框数组。然而,即使数组发生了变化,映射本身也不会发生变化,即使我已经将types变量设置为存储复选框选择结果的位置(data.Locations.arrLocations)。在这种情况下,如何获得正确的绑定?

我已经包括我的index.html和app.js文件如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <style>
  html, body {
    height: 100%;
    margin: 0;
    padding: 0;
  }
  #map {
    height: 100%;
  }
</style>
</head>
<body>
<!-- This is a *view* - HTML markup that defines the appearance of your UI -->
<div id='searchBar'>
    <p>Search: <strong data-bind="text: location"></strong></p>
    <p><input type='checkbox' data-bind='checked: Locations' value='gym'> Gyms </p>
    <p> <input type='checkbox' data-bind='checked: Locations' value='park'>Parks </p>
    <p> <input type='checkbox' data-bind='checked: Locations' value='store'> Stores </p>
    <p> <input type='checkbox' data-bind='checked: Locations' value='museum'> Museums </p>
    <p> <input type='checkbox' data-bind='checked: Locations' value='zoo'> Zoos </p>
    <p>Search: <input data-bind="value: location" /></p>
    <div data-bind='text: ko.toJSON($data.Locations)'></div>

</div>

<div id='map'></div>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?signed_in=true&libraries=places&callback=initMap" async defer></script>

<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js'></script>
<script type='text/javascript' src='js/app.js'></script>
</body>
</html>

app.js:

var data = {
    'Locations' : {
        'arrLocations': ['park', 'gym']
    }
};

function AppViewModel() {
    this.location = ko.observable("Barcelona, Spain");
    this.Locations = ko.observableArray(data.Locations.arrLocations);


}

var map;
var infowindow;
function initMap() {
  var barcelona = {lat: 41.383, lng: 2.183};
  map = new google.maps.Map(document.getElementById('map'), {
    center: barcelona,
    zoom: 15
  });
  infowindow = new google.maps.InfoWindow();
  var service = new google.maps.places.PlacesService(map);
  service.nearbySearch({
    location: barcelona,
    radius: 800,
    types: data.Locations.arrLocations,
  }, callback);
}
function callback(results, status) {
  if (status === google.maps.places.PlacesServiceStatus.OK) {
    for (var i = 0; i < results.length; i++) {
      createMarker(results[i]);
    }
  }
}
function createMarker(place) {
  var placeLoc = place.geometry.location;
  var marker = new google.maps.Marker({
    map: map,
    position: place.geometry.location
  });
  google.maps.event.addListener(marker, 'click', function() {
    infowindow.setContent(place.name);
    infowindow.open(map, this);
  });
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

您需要根据Locations的变化调整subscribe并相应地调整您的标记。要清除不需要的标记,您需要跟踪已添加的标记。我用markers数组做到了这一点。每次Locations更改时,所有标记都被删除,然后运行搜索并添加标记。

viewModel.Locations.subscribe(function (newValue) {
    console.debug("Changing", newValue);
    for (var i=0; i<markers.length; ++i) {
        markers[i].setMap(null);
    }
    markers = [];
    service.nearbySearch({
        location: barcelona,
        radius: 800,
        types: newValue
    }, callback);
});
viewModel.Locations.notifySubscribers();

notifySubscribers调用导致订阅在第一次运行时触发。

http://jsfiddle.net/53qfm5bz/1/