Что я хочу сделать, это создать поиск, который будет искать элементы, которые соответствуют критериям поиска. Например, если я хочу найти книгу под названием «песня льда и огня» ... «песни» должно быть достаточно, чтобы найти результаты фильтра. Критерии поиска - это поиск по названию книги

Я получаю свои данные из базы данных sql server, через контроллер mvc и на клиентском сайте с помощью этого метода, который на самом деле работает нормально и отображает данные в таблице (так как я тестирую только, если получаю эти данные).

PS: . Здесь важно то, что окончательный результат заключается в том, что я не отображаю все книги в какой-либо таблице / таблице и не выполняю поиск / фильтрацию по этой таблице, все это должно быть включено в поиск и только найдено методом поиска.

< Сильный > update1

self.search = function (value) {
            self.AllBooks.removeAll();
            for (var x in self.AllBooks) {
                if (self.AllBooks[x].toLowerCase().indexOf(value.toLowerCase()) >= 0) {
                    self.AllBooks.push(self.AllBooks[x]);
                }
            }
        }
0
aiden87 29 Авг 2017 в 08:33

3 ответа

Лучший ответ

Поскольку вы используете нокаут, я покажу вам более «реактивный», типичный нокаут-способ решения этой функции.

Ваша модель представления должна иметь одно частное свойство источник данных . В вашем случае список всех книг, который никогда не меняется. Вы не должны не очищать этот список .

Затем в другом свойстве вы сохраняете computed список данных (книг). Этот список принимает функцию filter и применяет ее к полному источнику данных.

Метод фильтра основан на вашем поисковом запросе (value, в вашем методе поиска). Давайте сделаем observable, чтобы мы знали, когда запускать обновления!

Вот пример с минимальными изменениями в вашем исходном коде , соединяющими все это вместе:

function Book(data) {
  var self = this;
  for (var key in data) {
    this[key] = ko.observable(data[key] == null ? "" : data[key]);
  }
}

function BookViewModel(data) {
  var self = this;
  self.title = ko.observable();
  
  self.searchQuery = ko.observable("");
  
  // The data source
  self.ListOfBooks = ko.observableArray([]);
  for (var i = 0; i < data.length; i++) {
    self.ListOfBooks.push(new BookList(data[i]));
  };
  
  // The filtered list
  self.searchResults = ko.pureComputed(function() {
    var query = self.searchQuery().trim().toLowerCase();
    
    if (!query) return [];
    
    return self.ListOfBooks().filter(function(list) {
      // The actual search method, easily moved or replaced
      // by some other logic
      var book = list.Book();
      
      return Object.keys(book).some(function(k) {
        return ko.unwrap(book[k]).toLowerCase().includes(query);
      })
    });
  });
}

function BookList(data) {
  var self = this;
  for (var key in data) {
    if (key != "Book")
      this[key] = ko.observable(data[key] == null ? "" : data[key]);
  }
  self.Book = ko.observable(data.Book)

}

var _allBooks = [ 
  { Book: { title: "To Kill a Mockingbird", author: "Harper Lee" }},
  { Book: { title: "Animal Farm", author: "George Orwell" }},
  { Book: { title: "The Lord of the Rings", author: "J.R.R. Tolkien" }}
];
ko.applyBindings(new BookViewModel(_allBooks == null ? new Array() : _allBooks));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>


<input type="search" data-bind="textInput: searchQuery">
<ul data-bind="foreach: searchResults">
  <li data-bind="with: Book">
    <span data-bind="text: title"></span>, by <span data-bind="text: author"></span>
  </li>
</ul>




<div data-bind="visible: !searchQuery()" style="opacity: .5">
  <p>(Try searching for these books:)</p>
  <ul data-bind="foreach: ListOfBooks">
  <li data-bind="with: Book">
    <span data-bind="text: title"></span>, by <span data-bind="text: author"></span>
  </li>
</ul>

Второй пример, в котором я также провел рефакторинг некоторых других частей, переместил некоторые вещи и использовал некоторые более современные функции js:

function Book(data) {
  for (var key in data) {
    this[key] = ko.observable(data[key] == null ? "" : data[key]);
  }
  
  this.searchString = ko.pureComputed(() =>
    Object
      .keys(data)
      .map(k => this[k])
      .map(ko.unwrap)
      .join("||")
      .toLowerCase()
  );
};

Book.fromData = data => new Book(data);
Book.matchesQuery = query => book => book.matchesQuery(query);

Book.prototype.matchesQuery = function(query) {
  return this.searchString().includes(query.trim().toLowerCase());
};

function BookViewModel(data) {
  this.searchQuery = ko.observable("");
  
  // The data source
  this.allBooks = ko.observableArray(data.map(Book.fromData));
  
  // The filtered list
  this.searchResults = ko.pureComputed(() => {
    return this.searchQuery()
      ? this.allBooks().filter(Book.matchesQuery(this.searchQuery()))
      : [];
  });
}

var _allBooks = [ 
  { title: "To Kill a Mockingbird", author: "Harper Lee" },
  { title: "Animal Farm", author: "George Orwell" },
  { title: "The Lord of the Rings", author: "J.R.R. Tolkien" }
];

ko.applyBindings(new BookViewModel(_allBooks));
* { box-sizing: border-box; position: relative;}

.searchwidget > input {
  width: 50%;
  padding: .5rem;
  border-radius: 0;
  outline: none;
  border: 1px solid #ccc;
  -webkit-appearance: none;
}

.searchwidget ul {
  margin: 0;
  padding: 0;
  position: absolute;
  width: 50%;
  
}

.searchwidget li {
  
  margin: 0;
  padding: .5em;
  list-style: none;
  
  border: 1px solid #ccc;
  border-top-width: 0;
  background: #efefef;
  opacity: .95;
  cursor: pointer;
}

.searchwidget li:nth-child(even) {
  background: #dfdfdf;
}

.searchwidget > li:hover {
  background: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div class="searchwidget">
  <input type="search" data-bind="textInput: searchQuery">
  <ul data-bind="foreach: searchResults">
    <li>
      <span data-bind="text: title"></span>, by <span data-bind="text: author"></span>
    </li>
  </ul>
</div>



<div data-bind="visible: !searchQuery()" style="opacity: .5">
  <p>(Try searching for these books:)</p>
  <ul data-bind="foreach: allBooks">
  <li>
    <span data-bind="text: title"></span>, by <span data-bind="text: author"></span>
  </li>
</ul>
1
user3297291 29 Авг 2017 в 10:51

В функции поиска вы перебираете массив «ListOfBooks» и добавляете элемент, соответствующий критериям поиска, в тот же массив ListOfBooks. Это дублирует элементы, которые соответствуют критериям.

var ListOfBooks = ["JavaBook", "C#Book", "JavaScriptBook", "HTMLBook"];
var value = "Java";
for (var x in ListOfBooks) {
  if (ListOfBooks[x].toLowerCase().indexOf(value.toLowerCase()) >= 0) {
    ListOfBooks.push(ListOfBooks[x]);
  }
}
console.log(ListOfBooks);

Если вы хотите получить результаты в отдельном массиве, вы можете сделать:

var ListOfBooks = ["JavaBook", "C#Book", "JavaScriptBook", "HTMLBook"];
var value = "Java";
var SearchResults = [];
for (var x in ListOfBooks) {
  if (ListOfBooks[x].toLowerCase().indexOf(value.toLowerCase()) >= 0) {
    SearchResults.push(ListOfBooks[x]);
  }
}
console.log(SearchResults);

Или, если вы хотите сохранить все элементы, соответствующие критериям, вы используете метод соединения:

var ListOfBooks = ["JavaBook", "C#Book", "JavaScriptBook", "HTMLBook"];
var value = "Java";
for (var x in ListOfBooks) {
  if (ListOfBooks[x].toLowerCase().indexOf(value.toLowerCase()) < 0) {
    ListOfBooks.splice(x, 1);
  }
}
console.log(ListOfBooks);
1
Raghunath Chary 29 Авг 2017 в 06:05

Используя Underscore JS, он более чистый и эффективный,

var _=require("underscore");
var ListOfBooks = ["JavaBook", "C#Book", "JavaScriptBook", "HTMLBook"];
var searchBook="Java";
var filteredBooks = _.filter(ListOfBooks, function(books) {
    return books.toLowerCase().indexOf(searchBook.toLowerCase() )>= 0;
});
console.log("filteredBooks " +JSON.stringify(filteredBooks));
-1
Sohan 29 Авг 2017 в 06:35