Список фильтров на основе более чем одного поля - PullRequest
0 голосов
/ 07 ноября 2018

Я перебираю список вакансий, и в этом списке реализован поиск. Поиск работает, но теперь он фильтрует список только по одному полю.

Вот мой список:

<ion-card *ngFor="let job of allJobs | search : searchTerm">
    <ion-grid>
    <ion-row>
        <ion-col>
        <div>
            <span> {{job.day | uppercase}}</span>
            <span> {{job.month | uppercase}}</span>
        </div>
        </ion-col>

        <ion-col>
        <div>
            <span>{{job.time}}</span>
            <span>{{job.name}}</span>
        </div>
        </ion-col>
    </ion-row>
    </ion-grid>
</ion-card>

Я сделал трубу для реализации поиска. Вот код для этого.

  transform(items: any[], terms: string): any[] {
    if(!items) return [];
    if(!terms) return items;
    terms = terms.toLowerCase();
    return items.filter( it => {
      return it.name.toLowerCase().includes(terms); // only filter name
    });
  }

Теперь список фильтруется только по полю name. Я хочу отфильтровать список по day, month и time.

Может кто-нибудь сказать мне, как это сделать?

Пример данных для рабочих мест. Работа - это массив объектов

   [  
      {  
         "id":10,
         "day":"Monday",
         "month":"June",
         "time":"10",
         "name":"John",
         "email":"john@gmail.com"
      },
      {  
         "id":11,
         "day":"Tuesday",
         "month":"May",
         "time":"12",
         "name":"Jane",
         "email":"jane@gmail.com"
      },
      {  
         "id":12,
         "day":"Friday",
         "month":"June",
         "time":"16",
         "name":"",
         "email":"john@gmail.com"
      },
      {  
         "id":13,
         "day":"Tuesday",
         "month":"August",
         "time":"21",
         "name":"",
         "email":"kevin@gmail.com"
      },
      {  
         "id":14,
         "day":"Saturday",
         "month":"December",
         "time":"12",
         "name":"Sam",
         "email":"sam@gmail.com"
      },

   ]

А searchTerm - это просто строка.

Как вы можете видеть, в примере данных больше полей, чем в HTML, но я пытаюсь искать только те поля, которые отображаются в HTML. Некоторые поля могут иметь нулевые значения (например, name в примере данных имеет два нулевых значения)

Я попробовал уже предоставленные решения, но ни одно из них не отвечает моим требованиям.

P.S: Где-то читал, что каналы - не лучший вариант для такой функциональности. Я готов реализовать эту логику и в классе.

Ответы [ 4 ]

0 голосов
/ 15 ноября 2018

Попробуйте объединить ваш includes с логическим оператором или (||):

transform(items: any[], terms: string): any[] {
    if (!items) return [];
    if (!terms) return items;
    terms = terms.toLowerCase();
    return items.filter(it => {
      return it.name.toLowerCase().includes(terms) ||
        it.day.toLowerCase().includes(terms) ||
        it.month.toLowerCase().includes(terms) ||
        it.time.toLowerCase().includes(terms)
    });
}

Этот оператор вернет true, если любой из includes вернет true. Таким образом, в основном любой элемент, который name, day, month или time содержит searchterm, будет возвращен каналом.

В этом решении предполагается, что name, day, month и time не равны нулю или не определены. Но я предполагаю, что это нормально, так как ваши примерные данные предполагают, что нулевые значения будут пустыми строками (""). Если мое предположение неверно, вам нужно проверить, присвоены ли значения, прежде чем обращаться к ним.

0 голосов
/ 07 ноября 2018

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

transform(items: any[], terms: string): any[] {
    if(!items) return [];
    if(!terms) return items;
    terms = terms.toLowerCase();
    return items.filter( it => {

       return keys(it).reduce((prev, key) => {
          return prev || key.toLowerCase().includes(term);
       }, false);
    });
}

Если ключи или Object.keys не работают, используйте следующий код вместо функции Reduce:

...
let bInclude = false;
for(let key in it){
  bInclude = bInclude || key.toLowerCase().includes(term);
}

return bInclude;
...
0 голосов
/ 08 ноября 2018

Попробуйте этот код .. это довольно просто.

  transform(items: any[], terms: string): any[] {
    if (!items) return [];
    if (!terms) return items;
    terms = terms.toLowerCase();
    terms = terms.trim();
    return items.filter(it => {
      if (it.day) {
        return it.day.toLowerCase().includes(terms);
      }
      if (it.month) {
        return it.month.toLowerCase().includes(terms);
      }
      if (it.time) {
        return it.time.toLowerCase().includes(terms);
      }
      if (it.name) {
        return it.name.toLowerCase().includes(terms);
      }
    });
  }

Если ваш JSON имеет нулевые значения, вы можете заменить его пустой строкой, используя следующий код:

items = JSON.parse(JSON.stringify(items).replace(/null/g, '""'));
0 голосов
/ 07 ноября 2018

Это не работает, потому что includes не проверяет несколько случаев. Вы не сказали, что внутри items Array, но если это строка, вы можете сделать это:

transform(items: any[], terms: string): any[] {
    if(!items) return [];
    if(!terms) return items;
    terms = terms.toLowerCase();
    return items.filter( it => {
      //if it is something like "Programmer 07 November 12:00PM"
      var informations = it.split(' '); //["Programmer", "07" ,"November" ,"12:00PM"]
      var termArray = terms.split(' ');
      var rightResult = true;
      for (var index in termArray) {
       if !(informations.include(termArray[index])) {
         rightResult = false;
       }
       return rightResult;


    });
  }
...