使用 Google Places API 和 KnockoutJS 列出地名

List Place Names Using Google Places API and KnockoutJS

我想检索 Google Places API 搜索返回的名称,并使用 KnockoutJS 列出它们。

我想使用 Google 个地点 API 搜索地点。我想在地图上标记这些地方,并使用 KnockoutJS 在无序列表中列出它们的名称。我可以将这些标记放在地图上,但无法使用 KnockoutJS 在无序列表中列出它们的名称。这是我的代码。

HTML:

<h4>Search Results<h4>
    <ul class="binding" data-bind="foreach: placesArray">
        <li class="binding" data-bind="text: $data">
            <span class="binding" data-bind="text: $index"></span>
        </li>
</ul>

JavaScript:

我发现非常困难的是我无法将placesArray = getNames(results)存储在全局变量placesArray中。我认为如果我在本地添加 knockoutJS 可能会起作用,但是 ko.applyBindings 如果我第二次搜索会导致错误。

let placesArray;
function searchPlaces() {
    let bounds = map.getBounds();
    hideMarkers(placeMarkers);
    let placesService = new google.maps.places.PlacesService(map);
    let placeName = placeInput.value;
    placesService.textSearch({
        query: placeName, // placeName is a string like "restaurants"
        bounds: bounds
    }, function(results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            createMarkers(results);
            placesArray = getNames(results);
            // placesArray is an array of strings like ["McDonalds", "KFC", "Wendy's",...], I want to list them in <li> //
        }
    });
}

function getNames(placesArray) {
    let placeNamesArray = [];
    for (let i=0; i < placesArray.length; i++) {
        let name = placesArray[i].name;
        placeNamesArray.push(name);
    }
    return placeNamesArray;
}

如果我在本地引入 KnockoutJS,名称会正确列出,但只有一次,如果我 运行 第二次使用此功能。 ko.applyBindings 会抛出错误,因为我多次将绑定应用到相同的元素。

function searchPlaces() {
    let bounds = map.getBounds();
    hideMarkers(placeMarkers);
    let placesService = new google.maps.places.PlacesService(map);
    let placeName = placeInput.value;
    placesService.textSearch({
        query: placeName,
        bounds: bounds
    }, function(results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            createMarkers(results);
            let placesArray = getNames(results);
            let SimpleListModel = function() {
                this.placesArray = ko.observableArray(placesArray);
            }
            ko.applyBindings(new SimpleListModel());
        }
    });
}

您需要创建一个带有属性和方法的视图模型,并且它应该只被实例化一次。像这样:

function ViewModel() {
    var vm = this;

    vm.placesArray = ko.observableArray();

    vm.getNames = function () {
        let placeNamesArray = [];
        for (let i=0; i < placesArray.length; i++) {
            let name = placesArray[i].name;
            placeNamesArray.push(name);
        }
        return placeNamesArray;
    };

    vm.getPlaces = function () {
        let bounds = map.getBounds();
        let placesService = new google.maps.places.PlacesService(map);
        let placeName = placeInput.value;

        hideMarkers(placeMarkers);

        placesService.textSearch({
            query: placeName,
            bounds: bounds
        }, function(results, status) {
            if (status == google.maps.places.PlacesServiceStatus.OK) {
                createMarkers(results);
                vm.placesArray(vm.getNames(results));
            }
        }); 
    };
}

ko.applyBindings(new ViewModel());

注意这里还有很多未定义的变量(例如,您没有提供 createMarkershideMarkers 函数,mapplaceMarkers 将是也未定义),所以这段代码将无法工作,但这应该是它的要点。

您可能还应该在视图模型上将 placeInput 设置为 属性(并使用 textInput 绑定将输入字段绑定到它),并且您可能想要变化时执行getPlaces函数,用Knockout也可以轻松完成。

viewmodel 和 Knockout observable 的想法是,您可以在获得任何新信息时更新它,并将反映在 HTML 中。因此,您最初可以创建一个空的可观察对象,稍后用您搜索的值填充它。

let SimpleListModel = function() {
    this.placesArray = ko.observableArray();
}
let modelInstance = new SimpleListModel();
ko.applyBindings(modelInstance);

function searchPlaces() {
    let bounds = map.getBounds();
    hideMarkers(placeMarkers);
    let placesService = new google.maps.places.PlacesService(map);
    let placeName = placeInput.value;
    placesService.textSearch({
        query: placeName,
        bounds: bounds
    }, function(results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            createMarkers(results);
            let placesArray = getNames(results);
            modelInstance.placesArray(placesArray);
        }
    });
}