如何过滤/搜索列表项和标记

时间:2017-10-30 09:35:23

标签: javascript knockout.js

目标是过滤列表元素和相应标记的显示。我无法理解逻辑的错误。搜索输入应该过滤,当你撤消/取消搜索输入时,列表应该重新出现标记。

HTML:

enter <html>
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title> Neighborhood Map</title>

 <link href="style.css" rel="stylesheet">
 <script src="js/jquery-3.2.1.js"></script>
 <script src="js/knockout-3.4.0.js"></script>
</head>

<body>
 <div class="container">
  <div class="row">
    <div id="sidebar" class="col-xs-12 col-sm-5 col-md-3">
      <h1 id="header">Chennai City Cultural Hubs</h1>

      <div class="search-box">
       <input class="text-search" type="text" placeholder="Enter here" data-
        bind="textInput: query">
      </div>
      <div class= "list-box">
       <div class="menu" data-bind="foreach: filteredItems">
       <a  class="menu-item"data-bind="text: title, click: $parent.setLoc" >
       </a>
       </div>
    </div>
  </div>

 <div class="col-xs-12 col-sm-6 col-md-8">
    <div id="map"></div>
 </div>

 </div>
 <script src="js/app.js"></script>
 </body>
 </html>

JS:

function appViewModel() {
    var self = this;
    this.query = ko.observable('');
    var filter = self.query().toLowerCase();

    this.locationArray = ko.observableArray([]);
    locations.forEach(function (item) {
        self.locationArray().push(item);
    });

    self.setLoc = function (clickedLoc) {
        var clickedData = clickedLoc.marker;
        google.maps.event.trigger(clickedData, 'click')
    };

    this.filteredItems = ko.computed(function () {
        if (!this.filteredItems) {
            return self.locationArray();
        } else {
            return ko.utils.arrayFilter(self.locationArray(), function (item) {
                var result = (item.title.toLowerCase().indexOf(filter) > -1)
                item.marker.setVisible(result);
                return result;
            });
        }
    }, self);
};
ko.applyBindings(new appViewModel());

解释和解决方案将非常有用。

1 个答案:

答案 0 :(得分:0)

的问题:

  • 您的filter变量无法观察,因此在实例化后不会更新。它总是一个空字符串,因为当您分配它时,query()会返回""
  • 检查计算中的!this.filteredItems没有做任何事情,因为它永远不会是假的。 (filteredItemsko.computed个实例,评估为true

解决方案

您可以将filteredItems重写为:

this.filteredItems = ko.computed(function () {
  var q = this.query().toLowerCase();
  if (!q) {
    // TODO (?): reset all `setVisible` props.
    return this.locationArray();
  }

  return this.locationArray()
    .filter(function(item) {
      var passedFilter = item.title.toLowerCase().indexOf(q) > -1;
      item.marker.setVisible(passedFilter);
      return passedFilter;
    });
}, self);

通过调用query,您可以为搜索输入中的任何更改创建依赖项。通过调用locationArray,您可以确保在数据源发生更改时进行更新。请注意,即使清除查询,您也需要确保执行setVisible逻辑...

备注&amp;提示

  • 如果需要,可以将Array.prototype.filter换成ko.utils.arrayFilter,但现在广泛支持.filter方法。
  • 您可以创建更多(纯)计算以分离逻辑。 (例如:const lowerQuery = ko.pureComputed(() => this.query().toLowerCase())
  • 我不会在过滤器中调用setVisible,因为它会产生意想不到的副作用。为什么不把它作为computed