Faizan Saiyed
Faizan Saiyed

Reputation: 852

Search in Array of objects on multiple values

I have array of objects:

[
  {
    "caseNumber": 123,
    "patientName": "John Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  },
  {
    "caseNumber": 123,
    "patientName": "John Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  },
  {
    "caseNumber": 123,
    "patientName": "John Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  }
]

I have a search bar on top and want to search for any matching string from any key which I provide. For example: I want to search from caseNumber, patientName & reader so I will call my filter function as filter(allCases, caseNumber, patientName, reader) I tried using Angular pipers but it is just working for first two keys.

I tried below code:

this.activeCases = this.filterPipe.transform(
      activeCases,
      this.searchUser,
      this.isCurrentUserTech ? 'readerName' : 'techName',
      'patientFullName',
      'caseNumber'
    );

And my pipe function:

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {
  transform(items: any[], value: string, label: string, optionalLabel?: string, optionalLabel2?: string, optionalValue?: string): any[] {
    if (!items) {
      return [];
    }
    if (!optionalValue && !value) {
      return items;
    }

    if ((value === '' || value == null) && (optionalValue === '' || optionalValue == null)) {
      return [];
    }

    if (optionalValue && optionalLabel) {
      this.filterByValue(value, items, label, optionalLabel, optionalValue);
    } else if (optionalLabel) {
      return items.filter(e => (e[optionalLabel] + ', ' + e[label]).toLowerCase().indexOf(value.toLowerCase()) > -1);
    } else if (optionalLabel && label && value) {
      return items.filter(item => {
        let object: any = { item1: optionalLabel, item2: label };
        if (optionalLabel2) {
          object = { item1: optionalLabel, item2: label, item3: optionalLabel2 };
        }
        for (const property in object) {
          if (item[object[property]] === null) {
            continue;
          }
          if (item[object[property]].toString().toLowerCase().includes(value.toLowerCase())) {
            return true;
          }
        }
        return false;
      });
    } else {
      return items.filter(e => {
        const tempValue = e[label] ? e[label].toLowerCase() : '';
        return tempValue.indexOf(value.toLowerCase()) > -1;
      });
    }
  }

  filterByValue(value, items, label, optionalLabel, optionalValue) {
    if (value) {
      return items.filter(e => {
        const firstLabel = e[label] ? e[label].toLowerCase() : '';
        const secondLabel = e[optionalLabel] ? e[optionalLabel].toLowerCase() : '';
        const firstValue = value ? value.toLowerCase() : value;
        const secondValue = optionalValue ? optionalValue.toLowerCase() : optionalValue;
        let firstCheck = false;
        let secondCheck = false;
        if (firstLabel && firstValue) {
          firstCheck = firstLabel.includes(firstValue);
        }
        if (secondLabel && secondValue) {
          secondCheck = secondLabel.includes(secondValue);
        }
        return firstCheck && secondCheck;
      });
    } else {
      return items.filter(e => {
        const tempValue = e[optionalLabel] ? e[optionalLabel].toLowerCase() : '';
        return tempValue.indexOf(optionalValue.toLowerCase()) > -1;
      });
    }
  }
}

What am I missing? I can also use lodash

Upvotes: 5

Views: 4957

Answers (2)

hsjeevan
hsjeevan

Reputation: 306

const data = [{
    caseNumber: 123,
    patientName: 'Adam',
    technician: 'Jasicca',
    reader: 'Potter',
  },
  {
    caseNumber: 456,
    patientName: 'John Doe',
    technician: 'Kevin',
    reader: 'Harry',
  },
  {
    caseNumber: 789,
    patientName: 'Ram',
    technician: 'Bob',
    reader: 'Jade Boe',
  },
];

const input = document.querySelector('input');
const log = document.getElementById('log');

function searchArray(e) {
  let filtered = [];
  const input = e.target.value.toLowerCase();
  if (input) {
    filtered = data.filter((el) => {
      return Object.values(el).some((val) =>
        String(val).toLowerCase().includes(input)
      );
    });

    log.textContent = JSON.stringify(filtered);
  }
}
<input placeholder="Enter some text" name="name" onkeyup="searchArray(event)" />
<p id="log"></p>

Upvotes: 3

Terry Lennox
Terry Lennox

Reputation: 30675

You could use a search object, for example { patientName: 'John', technician: 'Jasmin' } and supply it to a findResults function.

We'd use Array.filter and Array.every to ensure all search criteria are met.

If you want results to show for any search criteron, you could use Array.some instead of Array.every.

Something like:

let arr = [
  {
    "caseNumber": 123,
    "patientName": "John Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  },
  {
    "caseNumber": 456,
    "patientName": "John Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  },
  {
    "caseNumber": 789,
    "patientName": "Jim Doe",
    "technician": "Jasmin Joe",
    "reader": "Jade Boe"
  }
];

// Customize as appropriate.
// Currently performs a case-insensitive match
function searchMatch(target, search) {
    search = String(search).trim().toLowerCase();
    return String(target).toLowerCase().includes(search);
}

function findResults(arr, searchObj) {
    return arr.filter(el => { 
        return Object.entries(searchObj).every(([key, value]) => searchMatch(el[key], value));
    })
}

console.log("Result 1:", findResults(arr, { patientName: 'JIM'}));
console.log("Result 2:", findResults(arr, { patientName: 'John Doe'}));
console.log("Result 3:", findResults(arr, { patientName: 'jim doe', technician: 'jasmin'}));
console.log("Result 4:", findResults(arr, { caseNumber: '123' }));
console.log("Result 5:", findResults(arr, { technician: 'Mark Johnson' }));

 

Upvotes: 2

Related Questions