methuselah
methuselah

Reputation: 13206

Remove null entries from array of objects

I have the following array of objects below (components) and I want to remove all the null entries. How can I go about doing it? I am trying the following:

  static deleteNullComponents(components) {
    return components.filter(function (el) {
      return el['components'] != null;
    });
  }

but I get the error: TypeError: components.filter is not a function. How can I fix it?

[
  {
    "components": [
      null,
      {
        "componentId": "navbar-zJNm0HaP",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      null,
      null,
      {
        "componentId": "features-MJU8gcYR",
        "componentIndex": 5,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "features-2hsUdwaT",
        "componentIndex": 7,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "footer-dLvoLZ16",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "Home"
  },
  {
    "components": [
      null,
      {
        "componentId": "navbar-UBdYplVp",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      {
        "componentId": "features-mmEzByeO",
        "componentIndex": 3,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "features-GZKgh9lV",
        "componentIndex": 5,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "footer-IyrNODRQ",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "About"
  }
]

Upvotes: 0

Views: 90

Answers (4)

DanG
DanG

Reputation: 91

You're only stepping one layer into that object. Assuming that you don't care about the name property you need something like:

// take the array of objects and iterate over them
firstLevelArray.map((secondLevelArray) => {
  // grab each components array in the array of objects, and filter it for null
  return secondLevelArray['components'].filter((possibleComponent) => {
    return possibleComponent != null;
  })
});

However you probably want to keep the name, and in any case this is a pretty rigid way to do things as you're assuming your current data structure. Here's a quick and dirty recursive method, which should handle an arbitrary number of nestings... however recursion isn't fully properly implemented in javascript. You SHOULD be using a library like underscore for deep comparison. I wrote this up for fun and to be illustrative, as reading library code can be somewhat difficult if you're new to javascript (and even then for my little brain).

Though it's likely already clear, what we're doing here is stepping into each item in your json, checking if it's null, if not then if it's an array or an object: visit each item of that, and so on.

let deepRemoveNull = function(x) { 
    if (x === null) {
        return;
    } 
    if (Array.isArray(x)) {
        let arr = [];
        for (const i of x) {
            if (x !== null) {
                let result = deepRemoveNull(i);
                // get rid of undefined
                if (result) {
                    arr.push(result);
                }
            }
        }
        return arr;
    } else if (typeof x === 'object') {
        let obj = {};
        for (const key in x) {
            if (x[key] !== null) {
                let result = deepRemoveNull(x[key]);
                // get rid of undefined
                if (result) {
                    obj[key] = result;
                }
            }
        }
        return obj;
    }
    return x;
}

If you pass in your object to the function above it should work for you. DO NOT USE THE ABOVE IN PRODUCTION CODE

Upvotes: 1

Joe
Joe

Reputation: 1

You could use a one-liner :

components = components.filter(function(el) { return el !== null }); 

Upvotes: -2

Jaromanda X
Jaromanda X

Reputation: 1

components are an array property inside an array items in pageComponents

So you'll need two loops (forEach/map/filter etc are really just iterating through an array)

So, for each item in the pageComponents array, you want to filter values in the components property of that item

Also, in the filter function, you don't need to return the original array, since you are not altering the original array, you are altering a nested array within it

class MyService {  
  static deleteNullComponents(components) {
    components.forEach(obj =>
      obj.components = obj.components.filter(item => item !== null)
    )
  }
}

let pageComponents = [
  {
    "components": [
      null,
      {
        "componentId": "navbar-zJNm0HaP",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      null,
      null,
      {
        "componentId": "features-MJU8gcYR",
        "componentIndex": 5,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "features-2hsUdwaT",
        "componentIndex": 7,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "footer-dLvoLZ16",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "Home"
  },
  {
    "components": [
      null,
      {
        "componentId": "navbar-UBdYplVp",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      {
        "componentId": "features-mmEzByeO",
        "componentIndex": 3,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "features-GZKgh9lV",
        "componentIndex": 5,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "footer-IyrNODRQ",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "About"
  }
]

MyService.deleteNullComponents(pageComponents)
console.log(pageComponents)

Upvotes: 1

Asleepace
Asleepace

Reputation: 3745

Looks like you are running filter on the wrong object, try the following:

NOTE: This will also modify the original components array that is passed into the deleteNullComponents, so it is unnecessary to re-assign components after the method call. If you don't want this behavior, take a look at the following thread:

How to deep clone an object in Javascript

class MyService {  
  static deleteNullComponents(components) {
    return components.map(obj =>
      obj["components"].filter(item => item !== null)
    )
  }
}

let pageComponents = [
  {
    "components": [
      null,
      {
        "componentId": "navbar-zJNm0HaP",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      null,
      null,
      {
        "componentId": "features-MJU8gcYR",
        "componentIndex": 5,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "features-2hsUdwaT",
        "componentIndex": 7,
        "componentName": "app-builder-features",
      },
      null,
      {
        "componentId": "footer-dLvoLZ16",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "Home"
  },
  {
    "components": [
      null,
      {
        "componentId": "navbar-UBdYplVp",
        "componentIndex": 1,
        "componentName": "app-builder-navbar",
      },
      null,
      {
        "componentId": "features-mmEzByeO",
        "componentIndex": 3,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "features-GZKgh9lV",
        "componentIndex": 5,
        "componentName": "app-builder-features"
      },
      null,
      {
        "componentId": "footer-IyrNODRQ",
        "componentIndex": 9,
        "componentName": "app-builder-footer",
      },
      null
    ],
    "name": "About"
  }
]

// no need to re-assign here, the original object is modified
pageComponents = MyService.deleteNullComponents(pageComponents)
console.log(pageComponents)

Upvotes: 1

Related Questions