Home > database >  How to filter the objects based on user input and map their corresponded array?
How to filter the objects based on user input and map their corresponded array?

Time:09-21

This is bugging me quite a bit. I hope someone can help me with it. I'm doing this in React.

Here is the data (objects that have an array inside):

{
   "Susan": {
      "likes": [
         "shopping",
         "skiing",
         "surfing"
      ],
      "hates": [
         "cycling",
         "reading",
         "cleaning"
      ]
   },
   "Andrew": {
      "likes": [
         "driving",
         "hiking",
         "coding"
      ],
      "hates": [
         "dancing",
         "running",
         "cleaning dishes"
      ]
   }
}

Now, in this case, I would like to display/map both arrays ("likes" and "hates") based on user choosing "Susan" or "Andrew". I just can't seem to logical connect this.

Let's say user input is a variable:

let input = "Susan"

I have something like:

Object.values(data).filter((val) => {
   if(input === val) {
      return val;
   }
}).map((obj) => {
   return ( 
      <div>
         <p> {obj.likes} </p>
         <p> {obj.hates} </p>
      </div>
);
})

I know there has to be some kind of binding with the keys, but I don't know how to do that.

Your help is very much appreciated!

CodePudding user response:

I think you may be overcomplicating this if I'm not misunderstanding the question. data['Susan'] will get you an entry with the 'likes' and 'hates' arrays. You can use it like this:

const data = {
    "Susan": {
       "likes": [
          "shopping",
          "skiing",
          "surfing"
       ],
       "hates": [
          "cycling",
          "reading",
          "cleaning"
       ]
    },
    "Andrew": {
       "likes": [
          "driving",
          "hiking",
          "coding"
       ],
       "hates": [
          "dancing",
          "running",
          "cleaning dishes"
       ]
    }
}
     
const createDiv = (name) => {
    let entry = data[name];
    return ( 
        <div>
            <p> {entry.likes} </p>
            <p> {entry.hates} </p>
        </div>
    );
}

let element = createDiv('Susan');

CodePudding user response:

You should filter your data as entries i.e. Object.entries so that you retain the object key (name) and the value (likes and dislikes).

I added a debounce to the input field so that entries only get filtered/rendered when the user stops typing.

const
  filteredResults = document.querySelector('#filtered-results'),
  searchTerm = document.querySelector('#search-term');

const render = () => {
  const filtered = searchTerm.value.trim().length
    ? Object.entries(data)
      .filter(([key, value]) => searchTerm.value.includes(key))
    : Object.entries(data);

  filteredResults.innerHTML = `
    <ul >
      ${filtered.map(([key, { likes, hates }]) => {
        return `
          <li>
            <h1>${key}</h1>
            <h2>Likes</h2>
            <ul >
              ${likes.map(like => `<li>${like}</li>`).join('')}
            </ul>
            <h2>Hates</h2>
            <ul >
              ${hates.map(hate => `<li>${hate}</li>`).join('')}
            </ul>
          </li>
        `;
      }).join('')}
    </ul>
  `;
};

const main = () => {
  render();
  searchTerm.addEventListener('keyup', handleKeyUp);
};

const debounce = (callback, wait) => {
  let timeoutId = null;
  return (...args) => {
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      callback.apply(null, args);
    }, wait);
  };
};

const handleKeyUp = debounce((event) => {
  render();
}, 500);

const data = {
  "Susan": {
    "likes": [ "shopping", "skiing", "surfing" ],
    "hates": [ "cycling", "reading", "cleaning" ]
  },
  "Andrew": {
    "likes": [ "driving", "hiking", "coding" ],
    "hates": [ "dancing", "running", "cleaning dishes" ]
  }
};

main();
*, *:before, *:after {
  box-sizing: border-box;
}

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

h1, h2 {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1rem;
}

.entries {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style-type: none;
  gap: 1rem;
  padding: 0.5rem;
}

.entries > li {
  display: flex;
  flex-direction: column;
  min-width: 20rem;
  background: #EEE;
  border: thin solid #AAA;
  padding: 0.5rem;
}

.entries li h1 {
  font-weight: bold;
  font-size: 1.25rem;
  margin: 0.25rem 0 0.5rem 0;
}

.entries li h2 {
  font-weight: bold;
  font-size: 1rem;
  margin: 0.125rem 0 0.25rem 0;
}

.sublist {
  margin: 0;
  padding: 0;
  list-style-type: none;
}

.sublist > li {
  display: inline-block;
  margin-right: 0.5rem;
  padding: 0.25rem;
  border: thin solid #AAA;
}
<input type="text" id="search-term" placeholder="Filter by name" />
<hr />
<div id="filtered-results"></div>

  • Related