0

I'm trying to filter a large array of objects that also have nested values.

I need to match shortName OR description OR isoCode. Some of the items may have 20+ countries but most have 1 to 5.

{
 countries: Array(1)
  0:
    description: "United Kingdom"
    isoCode: "GB"
  1:
    description: "Italy"
    isoCode: "IT"
 shortName: "AIB (NI)"
},
// * 2000
 

I've tried building on this with limited success.

  methods: {
    filterInstitutions: function (items: any, event: any): void {
      console.log(items, event.target.value);
      if (event === '') {
        newFunction(items);
      } else {
        this.listedInstitutions = items.filter((item: any) => {
          return item.shortName.toLowerCase().includes(event.target.value.toLowerCase());
        })
      }
    },
  },

I am building this in Vue (typescript) but understand its as much of a JS question than a Vue one.

Any suggestions welcome.

3 Answers 3

2

You will need to add in tests for the description and isoCode of your countries property to your filter function.

One way would be to use the Array's some() method which will test if any of the array element's match any test you setup in the callback. It will then return true if any do match and false if not.

let testValue = event.target.value.toLowerCase();
this.listedInstitutions = items.filter((item: any) => {
   //test the shortName
   let matchesShortName = item.shortName.toLowerCase().includes(testValue);

   //loop through countries and see if any description or isoCode match
   let matchesDescIsoCode = item.countries.some((item:any) => {
     let desc = item.description.toLowerCase();
     let code = item.isoCode.toLowerCase();
     return desc.includes(testValue) || code.includes(testValue);
   });
   return matchesShortName || matchesDescIsoCode;
})

Example

function doFilter(event, items) {
  let testValue = event.target.value.toLowerCase();
  let listedInstitutions = items.filter((item) => {
    let matchesShortName = item.shortName.toLowerCase().includes(testValue);
    let matchesDescIsoCode = item.countries.some((item) => {
      let desc = item.description.toLowerCase();
      let code = item.isoCode.toLowerCase();
      return desc.includes(testValue) || code.includes(testValue);
    });
    return matchesShortName || matchesDescIsoCode;
  });
  console.clear();
  console.log("Filtered List");
  console.log(listedInstitutions);
}

let someItems = [{
  countries: [{
      description: "United Kingdom",
      isoCode: "GB"
    },
    {
      description: "Italy",
      isoCode: "IT"
    }
  ],
  shortName: "AIB (NI)"
}, {
  countries: [{
      description: "United States",
      isoCode: "US"
    },
    {
      description: "Italy",
      isoCode: "IT"
    }
  ],
  shortName: "ABC (DE)"
}]
<input type="text" oninput="doFilter(event,someItems)">

Sign up to request clarification or add additional context in comments.

1 Comment

some() - I see. Thanks will be trying this later.
1

You could create an array of properties to search on within your object(s) and determine if any matches exist.

this.listedInstitutions = items.filter((item: any) => {
  return item.countries.filter(
    country => ['description', 'isoCode', 'shortName'].filter(prop => item.prop && item.prop.toLowerCase().includes(event.target.value.toLowerCase()).length > 0
  ).length > 0
})

3 Comments

isoCode and shortName are not properties of the item itself but of objects in a list of countries each item has.
@trixn You can just nest that in yet another filter comparing the length if all you're wanting is a true/false comparison. Updated answer.
Actually no this doesn't work either as you are still only checking item.prop which is in itself already wrong. It has to be item[prop] and then it still wouldn't work as doesn't compare the prop from the country but from the item which doesn't have description or isoCode.
1

Using filter() and some():

function filterInstitutions (items, {target: {value}}) {
  const isMatch = text => text.toLowerCase().includes(value.toLowerCase());

  return items.filter(({shortName, countries}) => (
    isMatch(shortName) || countries.some(({description, isoCode}) => (
      isMatch(description) || isMatch(isoCode)
    ))
  ));
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.