0

I have got an object, that may look like this:

{
  address: {
    street: undefined,
    country: 'GB'
  },
  givenname: 'Marko',
  surname: null,
}

I want to know if all fields are set or if at least one is null. Is there a smarter / shorter way to dot his in javascript than

address.street != null && address.country != null && givenname != null && surname != null

Maybe something that looks like this:

// this could return true or false?
nullCheck(address.street, address.country, givenname, surname)
Marian Rick
  • 3,350
  • 4
  • 31
  • 67
  • You don't have to explicitly check against `!= null`. You can rely on implicit conversion to Boolean and a [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) check: `if(address.streetl && address.country && givenname && surname)` – Scott Marcus Jul 23 '20 at 12:39
  • @ScottMarcus but empty strings will not pass this check. – Jorge Fuentes González Jul 23 '20 at 12:40
  • Your title is kind of misleading, since there are no `const`s in your code. Your property names are also invalid. – Heretic Monkey Jul 23 '20 at 12:40
  • 1
    Does this answer your question? [Determining if all attributes on a javascript object are null or an empty string](https://stackoverflow.com/questions/27709636/determining-if-all-attributes-on-a-javascript-object-are-null-or-an-empty-string) – Heretic Monkey Jul 23 '20 at 12:41
  • The given object is not valid. The `.` cannot by used in JavaScript identifiers. Do you mean `{ "address.street": undefined, "address.country": 'GB' }` or `{ address: { street: undefined, country: 'GB' } }`? – 3limin4t0r Jul 23 '20 at 12:42
  • This is very similar to: https://stackoverflow.com/a/63031063/697154 – Yoshi Jul 23 '20 at 12:46

4 Answers4

2

Yes, there is. You can use the Object data type, and the includes array method like this:

Object.values(your_object).includes(null)

This will return true if your object contains at least one null element and false if it doesn't contain any.

This answer only works for 1 level deep objects.

Object Documentation Array.includes Documentation

Alejov
  • 464
  • 6
  • 14
2

You can use the every method, given a list of variables to check, with a callback that checks for null.

let address = {
    street: undefined,
    country: 'GB'
  },
  givenname = 'Marko',
  surname = null;

console.log([address.street, address.country, givenname, surname].every(e => e !== null))

surname = "blah"

console.log([address.street, address.country, givenname, surname].every(e => e !== null))
Luke Storry
  • 6,032
  • 1
  • 9
  • 22
1

You can use .some

const hasAnEmptyValue = (obj) => Object.values(obj).some(value => !value)

const obj1 = {
  address: null,
  givenname: 'Rick',
  surname: 'Sanchez',
}

const obj2 = {
  address: 'Argentina',
  givenname: 'Rick',
  surname: 'Sanchez',
}
    
console.log(hasAnEmptyValue(obj1))

console.log(hasAnEmptyValue(obj2))
Mati Tucci
  • 2,826
  • 5
  • 28
  • 40
  • I'm curious. Why `!Boolean(value)` and not simply `!value`. Is there any moment where they return different values? Just to know. – Jorge Fuentes González Jul 23 '20 at 13:01
  • @JorgeFuentesGonzález yeah, should be the same. I was using `Boolean` because at first I was doing: `.some(Boolean)` but then I changed to return `!Boolean` – Mati Tucci Jul 24 '20 at 14:34
1

The first one is the typical way to go actually. Works fine specially if you have typings, like with TypeScript.

The second one is just the same but with a bit of overhead (each time you enter/exit a function, adss a bit of overhead), although is really small overhead only noticeable when you have tons of iterations. You can detect the arguments dynamically:

const nullobj = {
    value1: "yay",
    value2: "",
    value3: 23,
    value4: null
};
const obj = {
    value1: "yay",
    value2: "",
    value3: 23,
    value4: "ok"
};

function checkArgumentsNull(...args) {
    for (let v of args) {
        if (v == null) {
            return true;
        }
    }
    return false;
}

console.log("nullobj:", checkArgumentsNull(nullobj.value1, nullobj.value2, nullobj.value3, nullobj.value4));
console.log("obj:", checkArgumentsNull(obj.value1, obj.value2, obj.value3, obj.value4));

But if you are going to check dynamically for arguments, you can check dynamically for properties, which is easier. Just saw your edit and this one can be easily converted to a recursive one that will check for sub-objects. Actually all functions here can be converted to recursive ones following this principle:

const nullobj = {
    value1: {
        ok: "ok",
        notok: null
    },
    value2: "",
    value3: 23,
    value4: "ok"
};
const obj = {
    value1: {
        ok: "ok",
        notok: "no"
    },
    value2: "",
    value3: 23,
    value4: "ok"
};

function checkPropertiesNull(obj) {
    for (let v in obj) {
        if (obj[v] == null || (typeof obj[v] === "object" && checkPropertiesNull(obj[v]))) {
            return true;
        }
    }
    return false;
}

console.log("nullobj:", checkPropertiesNull(nullobj));
console.log("obj:", checkPropertiesNull(obj));

And for the sake of modern JavaScript, you can even pass an iterator, and you can check whatever iterable object you can imagine of (object, arrays, maps, sets, etc):

const nullobj = {
    value1: "yay",
    value2: "",
    value3: 23,
    value4: null
};
const obj = {
    value1: "yay",
    value2: "",
    value3: 23,
    value4: "ok"
};
const nullarr = ["ok", "yay", null];
const arr = ["ok", "yay", "yay2"];

function checkIteratorNull(it) {
    for (let v of it) {
        if (v == null) {
            return true;
        }
    }
    return false;
}

console.log("nullobj:", checkIteratorNull(Object.values(nullobj)));
console.log("obj:", checkIteratorNull(Object.values(obj)));
console.log("nullarr:", checkIteratorNull(nullarr));
console.log("arr:", checkIteratorNull(arr));
Jorge Fuentes González
  • 11,568
  • 4
  • 44
  • 64