2

I am new to lodash, and created a function that removes the key from the object where a value is null or blank. But when i am passing my object which contains some part as array it removes array and converts it into an object.

Below is my code which i tried:

     _.mixin({ 'removeFalsies': this.removeFalsies });
        _.mixin({
                removeEmptyObjects: this.removeEmptyObjects
          });

         removeFalsies (obj) {
    return _.transform(obj, function (o, v, k) {

      if (v && typeof v === 'object') {

        if (v !== '') {
          o[k] = _.removeFalsies(v);
        }

      } else if (v === false) {
        o[k] = v;
      } else if (v) {
        o[k] = v;
      }
    });
  }
  removeEmptyObjects (obj) {
    return _(obj)
      .pickBy(_.isObject)
      .mapValues(_.removeEmptyObjects)
      .omitBy(_.isEmpty)
      .assign(_.omitBy(obj, _.isObject))
      .value();
  }

Below is the JSON which i am providing to omit blank and null value, so it should remove all the properties from "smallMap" object as series, align are blank object and should remove height as well.

On the other hand, it should remove "mid" from heatrules as well as series1 from children array.

var finalProp = {
  "smallMap": {
    "series": {},
    "align": {},
    "height": ""
  },
  "series": [
    {
      "heatRules": [
        {
          "min": "#555",
          "mid": null
        }
      ],
      "mapPolygons": {
        "tooltipText": "{name}",
        "togglable": true
      },
      "id": "value"
    }
  ],
  "children": [
    {
      "type": "HeatLegend",
      "width": "100%",
      "series1": null
    }
  ]
}
_.removeEmptyObjects(_.removeFalsies(finalProp));

It is removing everything as expected but only 1 issue it is converting array to object.

It is providing below incorrect output instead of series: {0 : {}} it should provide series: [{}] and instead of children: {0 :{}} it should provide [{}].

{
      "series": {
        "0": {
          "heatRules": {
            "0": {
              "min": "#555"
            }
      },
      "mapPolygons": {
        "tooltipText": "{name}",
        "togglable": true
      },
      "id": "value"
    }
  },
  "children": {
    "0": {
      "type": "HeatLegend",
      "width": "100%"
    }
  }
}

i am not able to find where is the issue any help is appreciated.

Mayur
  • 1,123
  • 3
  • 22
  • 38

3 Answers3

1

You issue is in your function removeFalsies where you do not account properly for arrays. Remember Arrays are also objects and your check for if (v && typeof v === 'object') is not sufficient.

What happens is that you do:

if (v && typeof v === 'object') {
  if (v !== '') {
    o[k] = _.removeFalsies(v);
  }
}

Where when you pass an array in that _.transform the k is 0 and you end up creating an object with key 0 which value is then _.removeFalsies(v);

Just put a breakpoint or debugger in that if and you can easily see the issue.

Also note that lodash already has plenty of methods to check for objects like _.isObject as well as arrays _.isArray ... _.isString & _.isEmpty etc.

Akrion
  • 18,117
  • 1
  • 34
  • 54
1

main two problems one which was mention by @Akrion for that you can do something as below:

removeFalsies (obj) {

return _.transform(obj, function (o, v, k, l) {

    // here you have to check for array also as typeof will return object for array also
  if (v && _.isObject(v) && !_.isArray(v)) {

    if (v !== '' && !_.omitBy(v, _.isObject)) {
      o[k] = removeFalsies(v);
    }

  } else if(_.isArray(v)) {
  if(!o.hasOwnProperty(k)) o[k] = [];

  //And if it is array loop through it

  _.forEach(v, function(v1, k1) {
     o[k].push(removeFalsies(v1));
  });

  } else if (v === false) {
    o[k] = v;
  } else if (v) {
    o[k] = v;
  }
});
}

while calling function just try to remove mapValues as it create object and convert array in objects because of that your key 0 is getting converted to key

removeEmptyObjects =function (obj) {
      return _(obj).pickBy(_.isObject).omitBy(_.isEmpty).assign(_.omitBy(obj, _.isObject)).value();
}

Hope this will help you, not tested properly yes just short description.

user3458271
  • 638
  • 12
  • 31
0

If your code uses

typeof v === 'object'

it will return true for arrays.

To check for array, use

Array.isArray(t)

Treating array as object and iterating over keys will result in your issue.

Sample Function To Recurse But Not Process Arrays

function removeFalsies(obj) {
  return _.transform(obj, function(o, v, k, l) {
      if (Array.isArray(obj) {
          for (let arrItem of obj) {
            removeFalsies(arrItem);
          }
          return
        }
        // else not array...
      })
  }
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78