将KnockoutJS绑定到Google Maps InfoWindow内容

时间:2015-08-12 16:39:06

标签: javascript html google-maps knockout.js

在我使用Google Maps InfoWindow显示位置详细信息的项目中,我遇到了敲除绑定问题。我已经将所选位置的数据绑定到了InfoWindow的HTML内容,这似乎在开始时工作正常。

现在出现问题:只要InfoWindow关闭(例如按下x按钮),谷歌地图从DOM中完全删除html内容并再次添加,当InfoWindow是再次显示(例如,单击下一个标记时)。

这里的问题是,一旦元素从DOM中删除,绑定就会丢失,因此内容不再更新。

我知道如何重新应用绑定到这个确切的元素?调用ko.applyBindings()再次导致异常“你不能多次将绑定应用于同一个元素”。

这里是InfoWindow内容的HTML元素:

<div id="info-content" data-bind="if:selectedPlace">
  <div class="gm-iw gm-sm" data-bind="with:selectedPlace">
    <div class="gm-title" data-bind="text:name"></div>
    <div class="gm-basicinfo">
      <div class="gm-addr" data-bind="text:vicinity"></div>
      <div class="gm-website" data-bind="if:website"><a target="_blank" data-bind="attr: {href:website}, text:websiteText"></a></div>
      <div class="gm-phone" data-bind="text:formatted_phone_number"></div>
    </div>
    <div class="gm-rev" >
      <span data-bind="if:rating">
        <span class="gm-numeric-rev" data-bind="text:rating"></span>
        <div class="gm-stars-b">
          <div class="gm-stars-f" data-bind="style: { width: getStarWidth } "></div>
        </div>
      </span>
      <span data-bind="if:url"><a target="_blank" data-bind="attr: {href:url}">see more</a></span>
    </div>
  </div>

JS初始化函数和onClick函数:

// the initialize function gets called after ko.applyBindings(model)
ViewModel.prototype.initialize = function () {

    ... code to initialize map and search elements

    // instantiate an InfoWindow
    infoWindow = new google.maps.InfoWindow();
    infoWindow.setContent(document.getElementById('info-content'));

    ... 

}

// gets called for each place returned by the search, 
// koPlace is the knockout observable for a place returned by the search, 
// i is the index of the search result
function addMarker(koPlace, i) {

    // create a marker
    var m = new google.maps.Marker({
      title: koPlace.name(),
      position: koPlace.jsPlace.geometry.location,
      animation: google.maps.Animation.DROP,
    });
    m.koPlace = koPlace;
    koPlace.marker = m;
    markers[i] = m;

    google.maps.event.addListener(m, 'click', markerClicked);
    setTimeout(dropMarker(i), i * 100);
}

function markerClicked() {
    var koPlace = this.koPlace; // this refers to the marker object

    if (koPlace) { // just checking
        koPlace.selected(true); // this is used for highlighting.
        model.selectedPlace(koPlace); // this should set the binding.
        infoWindow.open(map, this);
    }
}

3 个答案:

答案 0 :(得分:1)

我想我会为我使用的这个问题添加另一个解决方案。

您可以设置内容字符串(如Nurik所述)并让它保留您的绑定,但还有一些额外的步骤。然后,您需要使用jQuery将字符串转换为DOM节点并重新应用knockout绑定:

function makeContent() {
    var html = '<div id="info-window-container" style="display:none;">' +
                    '<div id="info-content" data-bind="if:selectedPlace">' +
                    '...' +
                    '</div>' +
               '</div>';
    html = $parseHTML(html)[0];
    return html;
)}

function addMarker() {
    var infoWindow = new google.maps.InfoWindow();
    var m = new google.maps.Marker({
      title: koPlace.name(),
      ...
      content: makeContent()
    });
    m.koPlace = koPlace;
    koPlace.marker = m;
    markers[i] = m;

    google.maps.event.addListener(m, 'click', function() {
        infoWindow.setContent(this.content);
        infoWindow.open(map,this);
    )};

    ko.applyBindings(YourViewModel, m.content);
)}

答案 1 :(得分:0)

感谢您的提问。它很难:)如果你查看infoWindow的google文档,它表明你需要告诉函数内容的来源:

而非写作:infoWindow = new google.maps.InfoWindow(); infoWindow.setContent(document.getElementById('info-content'));

你可以考虑这个:

infowindow = new google.maps.InfoWindow({
    content: contentString 
});

当然你还需要定义contentString。

请查看此处的文档:https://developers.google.com/maps/documentation/javascript/examples/infowindow-simple

答案 2 :(得分:0)

似乎我通过将内容包装在另一个不可见的容器div中并在InfoWindow关闭时将DOM元素重新添加到容器中来找到解决方案。

HTML现在看起来像这样:

<div id="info-window-container" style="display:none;">
    <div id="info-content" data-bind="if:selectedPlace">
        ...
    </div>
</div>

我将此行添加到init函数:

google.maps.event.addListener(infoWindow, 'closeclick', closeInfoWindow);

这个函数让JS重新将infoWindow内容添加到DOM:

function closeInfoWindow() {
    document.getElementById('info-window-container').appendChild(infoWindow.getContent());
}

现在knockout按预期更新infoWindow内容,并在点击标记时正确显示。