2

I have an array of objects, I need to delete a complete object based on the id

Input :

 filters: [
    {
      key: "status",
      label: "En attente",
      value: "waiting",
      id: 0
    },
    {
      key: "dateDue[min]",
      label: "15/12/2019",
      value: "15/12/2019",
      id: 1
    },
    {
      key: "dateDue[max]",
      label: "02/02/2020",
      value: "02/02/2020",
      id: 2
    },
    {
      key: "bien",
      values: [
        {
          label: "Studio Bordeaux",
          value: 36,
          id: 3
        },
        {
          label: "Studio 2",
          value: 34,
          id: 184
        }
      ]
    },
    {
      key: "type",
      values: [
        {
          type: "receipts",
          label: "Loyer",
          value: "loyer",
          id: 4
        },
        {
          type: "receipts",
          label: "APL",
          value: "apl",
          id: 5
        },
        {
          type: "spending",
          label: "taxes",
          value: "taxes",
          id: 6
        }
      ]
    }
  ]

So I created a removeItem method with the id that must be deleted in parameters

removeItem method :

removeItem = (e, id) => {
const { filters } = this.state;

const remove = _.reject(filters, el => {
  if (!_.isEmpty(el.values)) {
    return el.values.find(o => o.id === id);
  }
  if (_.isEmpty(el.values)) {
    return el.id === id;
  }
});
this.setState({
  filters: remove
});

};

I use lodash to make my job easier and more specifically _.reject My issue is the following : I manage to correctly delete the classic objects for example

{
  key: "status",
  label: "En attente",
  value: "waiting",
  id: 0
}

but my method however does not work for objects of the following form

   {
      key: "bien",
      values: [
        {
          label: "Studio Bordeaux",
          value: 36,
          id: 3
        },
        {
          label: "Studio 2",
          value: 34,
          id: 184
        }
      ]
    },

currently the whole object is deleted and not only the object in the values array according to its id

Here is my codesandbox!

thank you in advance for your help

EDIT

I found a solution with lodash (compact), I share my solution here :

  removeIdFromCollection = id => {
    const { filters } = this.state;
    const newFilters = [];
    _.map(filters, filter => {
      if (filter.values) {
        const valuesTmp = _.compact(
          _.map(filter.values, value => {
            if (value.id !== id) return value;
          })
        );
        if (!_.isEmpty(valuesTmp)) {
          return newFilters.push({
            key: filter.key,
            values: valuesTmp
          });
        }
      }
      if (filter.id && filter.id !== id) return newFilters.push(filter);
    });
    return newFilters;
  };

  removeItem = id => e =>
    this.setState({
      filters: this.removeIdFromCollection(id)
    });

The values false, null, 0, "", undefined, and NaN are removed with lodash compact (_.compact(array))

Here is my updated codesandbox

Edit agilimo-filters

alexsouye
  • 700
  • 8
  • 19

3 Answers3

2

You will need to filter the filters array and each values separately. Below is a recursive function which will remove items with the given id from the filters array and from the values property.

PS. This example is not using Lodash as I think it is not needed in this case.

  removeIdFromCollection = (collection, id) => {
    return collection.filter(datum => {
      if (Array.isArray(datum.values)) {
        datum.values = this.removeIdFromCollection(datum.values, id);
      }

      return datum.id !== id;
    });
  }

  removeItem = (e, id) => {
    const { filters } = this.state;

    this.setState({
      filters: this.removeIdFromCollection(filters, id),
    });
  };
Chris
  • 6,331
  • 1
  • 21
  • 25
1

The problem would be the structure of the object. You'll need to refactor for that inconvenient array out of nowhere for uniformity:

// Example
filters: [
...
{
  key: "type",
  values: [
    {
      type: "receipts",
      label: "Loyer",
      value: "loyer",
      id: 4
    },
    ...
  ]
...
}

// could be

filters: [
...
{
 key: "type-receipts",
 label: "Loyer",
 value: "loyer",
 id: 4
}
...
]

Repeat the pattern on all of it so you could just use the native array filter like this:

const newFilters = filters.filter(v => v.id !== id);

this.setState({
  filters: newFilters,
});
crrmacarse
  • 1,176
  • 1
  • 8
  • 22
0

I found a solution with lodash, I share it with you here :

  removeIdFromCollection = id => {
    const { filters } = this.state;
    const newFilters = [];
    _.map(filters, filter => {
      if (filter.values) {
        const valuesTmp = _.compact(
          _.map(filter.values, value => {
            if (value.id !== id) return value;
          })
        );
        if (!_.isEmpty(valuesTmp)) {
          return newFilters.push({
            key: filter.key,
            values: valuesTmp
          });
        }
      }
      if (filter.id && filter.id !== id) return newFilters.push(filter);
    });
    return newFilters;
  };

  removeItem = id => e =>
    this.setState({
      filters: this.removeIdFromCollection(id)
    });

Here is my updated codesandbox

Edit here

alexsouye
  • 700
  • 8
  • 19