0

I am doing a to-do list app but I have trouble completing this. I am using a stupid method to remove the selected items. It works when I select the items sequentially but does not work to select non-sequentially.

For example- For sequentially: selected id:1,2,3,4, I filter both markers and isCheck are work.

For non-sequentially: selected id 1,3,4 It will show :

  • Uncaught TypeError: Cannot read properties of undefined (reading 'id')

I have two questions,

  1. Can I use for loop inside the filter? And how to use?
  2. How to solve the problem of undefined id?

Here is my code:

const [markers, setMarkers] = useState([]);

const [isCheck, setIsCheck] = useState([]);


const handleRemoveLocationAll = () => {
    

    setMarkers(
      markers.filter(
        (item) =>
          item.id.toString() !== isCheck[0].id &&
          item.id.toString() !== isCheck[1].id &&
          item.id.toString() !== isCheck[2].id &&
          item.id.toString() !== isCheck[3].id &&
          item.id.toString() !== isCheck[4].id &&
          item.id.toString() !== isCheck[5].id &&
          item.id.toString() !== isCheck[6].id &&
          item.id.toString() !== isCheck[7].id &&
          item.id.toString() !== isCheck[8].id
      )
    );

    
    // This is my selected item
    setIsCheck(
      isCheck.filter(
        (item) =>
          item.id.toString() !== isCheck[0].id &&
          item.id.toString() !== isCheck[1].id &&
          item.id.toString() !== isCheck[2].id &&
          item.id.toString() !== isCheck[3].id &&
          item.id.toString() !== isCheck[4].id &&
          item.id.toString() !== isCheck[5].id &&
          item.id.toString() !== isCheck[6].id &&
          item.id.toString() !== isCheck[7].id &&
          item.id.toString() !== isCheck[8].id
      )
    );
// Click Checkbox
  const handleClick = (e) => {
    const { id, checked } = e.target;
 
    setIsCheck([...isCheck, { id: id, checked: checked }]);

    if (!checked) {
      setIsCheck(isCheck.filter((item) => item.id !== id));
    }
  };
//And the component
<input
  type="checkbox"
  id={marker.id}
  name={marker.name}
  onChange={handleClick}
        />

Updated question- How I write something like that:

setMarkers(
      markers.filter((item) => {
        for (let i = 0; i < isCheck.length; i++) {
          item?.id.toString() !== isCheck[i]?.id;
        }
      })
    );

//to represent this
 setMarkers(
      markers.filter(
        (item) =>
          item.id.toString() !== isCheck[0]?.id &&
          item.id.toString() !== isCheck[1]?.id &&
          item.id.toString() !== isCheck[2]?.id &&
          item.id.toString() !== isCheck[3]?.id &&
          item.id.toString() !== isCheck[4]?.id &&
          item.id.toString() !== isCheck[5]?.id &&
          item.id.toString() !== isCheck[6]?.id &&
          item.id.toString() !== isCheck[7]?.id &&
          item.id.toString() !== isCheck[8]?.id
      )
    );
Lovelyzombie
  • 41
  • 1
  • 6
  • How are you creating the "isCheck" array? It seems as if you are missing some objects there. Please add that code to your answer. Once that's figured out, it's possible you might find the rest of your answer here: https://stackoverflow.com/questions/237104/how-do-i-check-if-an-array-includes-a-value-in-javascript. – computercarguy May 10 '22 at 20:34

1 Answers1

0

Q1 Can I use for loop inside the filter? And how to use?

Yes.

Your current filter code is a short version of running this

array.filter((element) => true) 
array.filter((element => { return true } )

both are equivalent

With the latter you could write more complex functions (see: When should I use a return statement in ES6 arrow functions)

So to use a loop you would just do

setMarkers(
    markers.filter(
      (item) => {

            /* loop here */ 

          return (
        item.id.toString() !== isCheck[0].id &&
        item.id.toString() !== isCheck[1].id &&
        item.id.toString() !== isCheck[2].id &&
        item.id.toString() !== isCheck[3].id &&
        item.id.toString() !== isCheck[4].id &&
        item.id.toString() !== isCheck[5].id &&
        item.id.toString() !== isCheck[6].id &&
        item.id.toString() !== isCheck[7].id &&
        item.id.toString() !== isCheck[8].id)
      }
    
    )
  );

Q2 How to solve the problem of undefined id?

This is because .id doesn't exist in one your objects. It seems you are trying to read id from an object that does not exist (thanks @compuercarguy for clarification)

Unsure if that is intended but you could solve this from erroring by using optional chaining

e.g. write this instead

item?.id.toString() !== isCheck[0]?.id

see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

Edit: to illustrate loop in your example

setMarkers(
    markers.filter(
      (item) => {
          for(let i = 0; i < isChecked.length; i++) {
              if(item.id.toString() ===  isCheck[i].id) {
                return false
              }
          }
          return true
      }

    )
  );
Bas
  • 1,353
  • 3
  • 7
  • 18
  • 1
    Actually, "Q2" is because they are trying to read the property `id` from an object that doesn't exist and is the thing that's "undefined", not that `id` is "undefined". If `id` was "undefined", then it would just return "null" or "undefined", not throw an error. – computercarguy May 10 '22 at 20:44
  • Thank you, you got my point, I solved the Q2 just put the "?" . However, for Q1, I still don't know how to use for loop to represent item.id.toString() !== isCheck[0].id && item.id.toString() !== isCheck[1].id to. item.id.toString() !== isCheck[i].id &&. Could you give me some hints? – Lovelyzombie May 10 '22 at 21:36