Как определить, что вызвало изменение вычисляемой наблюдаемой величины? KnockoutJS - PullRequest
0 голосов
/ 06 января 2020

Обзор проблемы

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

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

Filter select field

Вот как я определяю выбор:

// Javascript
let filters = ["All", "Pending", "Accepted", "Rejected", "Expired"];

// HTML
<select data-bind="options: filters, value: filter"> 
</select>

Когда пользователь выбирает значение, эта вычисленная наблюдаемая используется для фильтрации основного массива данных:

self.filteredItems = ko.computed(function() {
        var filter = self.filter();
        if (!filter || filter == "All") {
            return self.quotes();
        } else {
            return ko.utils.arrayFilter(self.quotes(), function(i) {
                console.log(i);
                return i.status() == filter;
            });
        }
    });

, как вы можете видеть, свойство status в массиве кавычек сравнивается со значением фильтра в выпадающем списке. Все отлично работает Но теперь я добавляю поиск по ключевым словам и в массив (как показано ниже):

keyword search

Я связал текстовое поле ключевого слова с наблюдаемой:

self.keyword = ko.observable();

Изменение кода для обработки поиска по ключевым словам

Я считаю, что мог бы легко изменить вычисляемый наблюдаемый код для обработки поиска по ключевым словам, изменив это значение:

return i.status() == filter;

на что-то вроде этого (по сравнению с другими свойствами в массиве)

return i.fullName() == keyword || i.amount() == keyword || ..etc

НО

Я не знаю, как определить, фильтровать ли массив по фильтру раскрывающийся список или отфильтруйте его по ключевому слову. Каким-то образом мне нужно знать, что вызвало изменение вычисляемой наблюдаемой величины, не так ли?

Есть идеи?

Вот модель полного представления:

// Quotes View Model

// +---------------------------------------------------------------------------+
// |  Quote View Model                                                         |
// |                                                                           |
// |  quotes-view-model.js                                                     |
// +---------------------------------------------------------------------------+
// |  Shows a list of all Quotes                                               |
// +---------------------------------------------------------------------------+/

let QuoteModel = function(id, quote_number, created_date, expiration_date, amount, client, status){

     this.id = ko.observable();
     this.quote_number = ko.observable(quote_number);
     this.created_date = ko.observable(created_date);
     this.expiration_date = ko.observable(expiration_date);
     this.amount = ko.observable(amount);
     this.client = ko.observable(client);
     this.status = ko.observable(status);

}



let ClientModel = function(id, fullName){
    this.id = ko.observable(id);
    this.fullName = ko.observable(fullName);
}

// Define Status Dropdown filters
let filters = ["All", "Pending", "Accepted", "Rejected", "Expired"];


function QuoteViewModel() {

    var self = this; // Scope Trick


    /* QUOTE Observables */
    self.quotes = ko.observableArray();
    self.clients = ko.observableArray();

    self.keyword = ko.observable();
    self.searchType = ko.observable();

    self.filters = ko.observableArray(filters);
    self.filter = ko.observable('');

    self.filteredItems = ko.computed(function() {
        var filter = self.filter();
        if (!filter || filter == "All") {
            return self.quotes();
        } else {
            return ko.utils.arrayFilter(self.quotes(), function(i) {
                console.log(i);
                return i.status() == filter;
            });
        }
    });

    /* GET PAGE DATA */

    /* CLIENTS */
           $.getJSON(apiCustomersAll,
            function(data) {
                var fullName;
                $.each(data,
                    function(key, val) {
                        fullName = val.first_name + " " + val.last_name;
                        self.clients.push(new ClientModel(val.id, fullName));
                    });
            });

          $.getJSON(apiQuotesAll,
            function(data) {
                var fullName;
                $.each(data,
                    function(key, val) {
                        fullName = self.getClientById(val.client_id);
                        console.log(`Full name is ${fullName}`);
                        self.quotes.push(new QuoteModel(val.id, 
                                                        val.quote_number, 
                                                        formatDate(val.created_date), 
                                                        formatDate(val.expiration_date), 
                                                        val.amount, 
                                                        fullName, 
                                                        val.status
                                                      ));
                    });
            });


        // Search Client Array, Return Full Name
        self.getClientById = function(id) {
            const client = self.clients().find(function(val){
                return val.id() == id;
            });

            if(client) {
                return client.fullName();   
            }

            return undefined;
            }



       self.search = function(){
         // to do
       }


}



ko.applyBindings(new QuoteViewModel());

1 Ответ

0 голосов
/ 07 января 2020

Использование только одного текстового поля для разрешения поиска в свободном тексте усложнит фильтр, я могу понять, почему Вы добавили наблюдаемую searchType. Но вы можете проверить, можно ли считать напечатанный текст сумма , а затем дифференцировать фильтр с помощью этой проверки. Я считаю, что фильтр более полезен, когда Вы проверяете, превышает ли сумма добавленное значение, вместо проверки на точное равенство, вплоть до Вас.

Более того: поскольку комбинация этих фильтров будет применена к две сущности (цитаты и клиенты) также вам решать, следует ли применять фильтр произвольного текста как пересечение или как объединение между двумя наборами данных. В моем предложении ниже я снова фильтрую полученный набор данных ( пересечение ):

var quoteStatusOptions = ["All", "Pending", "Accepted", "Rejected", "Expired"];

var data = {
  quotes: [{id: 1, client: 1, amount: 300, status: "Pending"},{id: 2, client: 3, amount: 200, status: "Accepted"},{id: 3, client: 2, amount: 100, status: "Expired"}],
  clients: [{id: 1, fullName: "Leanne Graham"},{id: 2, fullName: "Ervin Howell"},{id: 3, fullName: "Clementine Bauch"}]
};

function QuoteModel(data) {
  this.id = ko.observable(data.id);
  this.client = ko.observable(data.client);
  this.amount = ko.observable(data.amount);
  this.status = ko.observable(data.status);
}

function ClientModel(data) {
  this.id = ko.observable(data.id);
  this.fullName = ko.observable(data.fullName);
}

function QuoteViewModel(data) {
  var self = this;
  self.quotes = ko.observableArray(ko.utils.arrayMap(data.quotes, function(quote) {
    return new QuoteModel(quote);
  }));
  self.quoteStatusOptions = ko.observableArray(quoteStatusOptions);
  self.quoteStatusFilter = ko.observable("");
  self.clients = ko.observableArray(ko.utils.arrayMap(data.clients, function(client) {
    return new ClientModel(client);
  }));
  self.searchTextFilter = ko.observable("");
  
  self.filteredQuotes = ko.computed(function() {
    var quotes = self.quotes(); /* Track quotes array changes */
    var quoteStatusFilter = self.quoteStatusFilter(); /* Track quote status filter changes */
    var clients = self.clients(); /* Track clients array changes */
    var searchTextFilter = self.searchTextFilter(); /* Track text filter changes */
    
    var isAmount = !isNaN(parseFloat(searchTextFilter)) && isFinite(searchTextFilter);
    
    var filteredQuotes = ko.utils.arrayFilter(quotes, function(quote) {
      var includeAll = !quoteStatusFilter || quoteStatusFilter === "All";
      var includeByStatus = includeAll || quote.status.peek() === quoteStatusFilter;
      var includeByAmount = parseFloat(quote.amount.peek()) >= parseFloat(searchTextFilter);
      return isAmount ? includeByStatus && includeByAmount : includeByStatus;
    });
    
    var filteredClients = ko.utils.arrayFilter(clients, function(client) {
      var includeAll = searchTextFilter === "";
      var includeByName = ~client.fullName.peek().toLowerCase().indexOf(searchTextFilter.toLowerCase());
      return isAmount ? true : includeAll || includeByName;
    });

    var result = [];
    for(var i=0, l=filteredQuotes.length; i<l; i++) {
      var clientId = filteredQuotes[i].id.peek();
      for(var j=0, k=filteredClients.length; j<k; j++) {
        var id = filteredClients[j].id.peek();
        if(clientId === id) {
          result.push(filteredQuotes[i]);
        }
      }
    }
    return result;
  });
  
  self.clientFullName = function(id) {
    var result = ko.utils.arrayFirst(self.clients(), function(client) {
      return client.id.peek() === id.peek();
    });
    return result.fullName.peek();
  }
}

$(document).ready(function() {
  ko.applyBindings(new QuoteViewModel(data));
});
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
</head>

<body>
  <div>
    <select data-bind="options: quoteStatusOptions, value: quoteStatusFilter"></select>
    <input type="text" data-bind="textInput: searchTextFilter">
  </div>
  <ul data-bind="foreach: filteredQuotes">
    <li>
      <span data-bind="text: status"> </span>
      <span data-bind="text: id"> </span>:
      <span data-bind="text: $parent.clientFullName(id)"> </span>
      $<span data-bind="text: amount"> </span>
    </li>
  </ul>
</body>

</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...