Установка значения наблюдаемого, которое не обновляется в представлении

#javascript #google-maps-api-3 #knockout.js

#javascript #google-maps-api-3 #knockout.js

Вопрос:

У меня есть куча точечных объектов (маркеров на картах Google), я настраиваю прослушиватель событий щелчка, который установит глобальную переменную «currentPlace» равной объекту Point, на который нажимается, затем я оборачиваю currentPlace в observable, надеясь, что представление изменится, например, появится боковое меню, которое отобразитинформация об этом точечном объекте.

 "use strict";
var currentPlace;
...

function initMap() {
map = new google.maps.Map(mapDiv, {
    zoom: 12,
    center: center,
    disableDefaultUI: true,
    draggable: true,
    google.maps.event.addListenerOnce(map, "idle", function() {
      var viewModel = new ViewModel(collection);
        ko.applyBindings(viewModel);
    });
}

var Point = function(place) {
    var self = this;
    self.name = place.name;
    self.pos = place.pos;
    self.type = place.type;
    self.description = place.description;
    self.clicked = map.getZoom();
    /**
        Create a marker for this destination.
  */
    self.marker = new google.maps.Marker({
        map: map,
        position: place.pos,
        title: place.name,
        icon: image,
        optimized: false,
        animation: google.maps.Animation.DROP
    });

    self.isVisible = ko.observable(false);
    /**
        Toggle for the visibility of each marker on map.
  */
  self.isVisible.subscribe(function(currentState) {
    if (currentState) {
      self.marker.setMap(map);
    } else {
      self.marker.setMap(null);
    }
  });

  self.isVisible(true);

  /**
        To re position the target marker and the map view to compensate for the shifted map view panel when the search menu pushes in from the left when the location is being clicked on the menu.
  */
    self.focusSearch = function() {
        map.setZoom(16);
        map.setCenter(self.marker.position);
        map.panBy(200,0);
        self.open();
    }
    /**
        To re position the target marker and the map view to compensate for the shifted map view panel when the menu slides in from the left when the location is being clicked on the menu.
  */
    self.focus = function() {
        map.setZoom(16);
        map.setCenter(self.marker.position);
        map.panBy(-200, 0);
        self.open();
    }
    /**
        Display the name and a brief description of the location in a infowindow for the corresponding marker. Also checks if the map view, in this case the zoom level has changed, if so then change the map view and re center it to the marker of the loaction that is selected. Applies to only when the regular menu is active.
    */
    self.open = function() {
        var contentString = "<h2>"   place.name   "</h2><br>";
        infowindow.setContent(contentString   place.description);
        infowindow.open(map, self.marker);
    }
    /**
        Dismiss the infowindow.
    */
    self.close = function() {
        infowindow.close();
        self.marker.setAnimation(null);
    }
    /**
        Additional event listeners for the marker.
    */
    self.marker.addListener("mouseover", function() {
        self.open();
        self.marker.setAnimation(google.maps.Animation.BOUNCE);
    });

    self.marker.addListener("mouseout", function() {
        self.marker.setAnimation(null);
    });

    self.marker.addListener("click", function() {
        currentPlace = self;
        map.setZoom(16);
        map.setCenter(self.marker.position);
        pushLeft.close();
        slideLeft.close();
        slideBottom.open();
        self.open();
    });
}
/**
        This is our ViewModel that handles displaying a menu of destinations, filter/search through the menu and finally displaying markers of these destinations on the map.
*/
var ViewModel = function(list) {
    var self = this;
    /**
     * Create a Place object for each object in the initial array and
     * place them in a new observable array.
    */
    self.allPlaces = ko.observableArray(list.map(function(place) {
        return new Point(place);
    }));

    self.search = ko.observable("");
    currentPlace = self.allPlaces()[0];
    self.selected = ko.observable();


    /**
     * Filter locations out of the menu view for any unmatched results.
     * Filter by name, description and type.
    */
    self.searchResult = ko.pureComputed(function() {
        var q = self.search().toLowerCase();
        return self.allPlaces().filter(function(place) {
            return ((place.name.toLowerCase().indexOf(q) >= 0) || (place.description.toLowerCase().indexOf(q) >= 0) || (place.type.toLowerCase().indexOf(q) >= 0));
        });
    });
    /**
     * Filter markers out of the map view for any unmatched results.
     * Filter by name, description and type.
    */
    self.filterMarkers = ko.computed(function () {
    var q  = self.search().toLowerCase();
    return ko.utils.arrayFilter(self.allPlaces(), function (place) {
        var doesMatch = ((place.name.toLowerCase().indexOf(q) >= 0) || (place.description.toLowerCase().indexOf(q) >= 0) || (place.type.toLowerCase().indexOf(q) >= 0));
        place.isVisible(doesMatch);
        return doesMatch;
    });
  });
}
  

Комментарии:

1. Почему это currentPlace глобальное, и почему оно не является наблюдаемым?

Ответ №1:

Нокаут таким образом не работает. Единственный способ привязать графический интерфейс к вашей модели представления — напрямую использовать observable.

В вашем случае лучше всего было бы переместить вашу глобальную переменную currentPlace в модель представления в качестве наблюдаемой. Чтобы получить к нему доступ позже, создайте глобальный экземпляр вашей модели представления.

 var vm = new ViewModel();

// Later on, access currentPlace this way:
vm.currentPlace();
  

Комментарии:

1. Вы были правы! Оказывается, мне понадобилось всего 3 дополнительные строки кода, чтобы заставить его работать. объявите var ViewModel в самой внешней области, чтобы точечный объект мог иметь к нему доступ. Затем внутри ViewModel выполните self.selected = ko.observable(self.allPlaces()[0]); чтобы установить начальный выбранный объект, который необходим, потому что, если я оставлю observable пустым, модель представления выдаст ошибку, поскольку я привязываю selected к html. наконец, в прослушивателе четного щелчка маркера добавьте ViewModel.selected = self, чтобы выбранный наблюдаемый объект обновлялся при каждом нажатии на маркер. Спасибо!