1

In an API response, I want to check if a variable exists. If it doesn't, I want to assign it a blank value:

if(!data3.fields[i+2].values.value[0]) {
  data3.fields[i+2].values.value[0] = "";
} else {
  break;
}

Error in the console is:

Uncaught TypeError: Cannot read property 'value' of undefined

This confuses me because I thought that's exactly what my if the statement was checking. Any ideas what's going on here?

Ivan
  • 34,531
  • 8
  • 55
  • 100
Sartorialist
  • 291
  • 2
  • 18
  • `data`, `fields`,`fields[i+2]`,`values` or `value` could all be undefined in that query – Liam Jun 22 '18 at 14:47
  • Possible duplicate of [Detecting an undefined object property](https://stackoverflow.com/questions/27509/detecting-an-undefined-object-property) – Liam Jun 22 '18 at 14:48

4 Answers4

1

The if check won't protect you from trying to use an undefined variable. In your instance the values property is undefined. If you wanted to test for that you would need to first check that specific property

if(data3.fields[i+2].values !== undefined && data3.fields[i+2].values.value[0]){
   //do something with data3.fields[i+2].values.value[0]
}

additionally, if you are in a scenario where you don't even know if data3 exists (for example you are checking for the existence of a third party script, or something else in your environment) you would need to use the typeof operator to be safe. E.G.

if(typeof(ga) !== 'undefined'){ //typeof returns a string. This would be testing for google analytics on a page.
dgeare
  • 2,618
  • 5
  • 18
  • 28
0

It doesnt work like PHP does (which checks the whole 'chain'). In your example, you actually check if .value[0] of values exists, but dont check if values exists. The full version should be:

  if( data3 && && data3.fields[i+2] && data3.fields[i+2].values && !data3.fields[i+2].values.value[0]) {}

In your code ata3.fields[i+2].values is undefined, and you're trying to access value[0] of 'undefined'


Or slightly more simplefied, if you wand to test if d has a value, you have to make sure that a, b and c aldo have a value:

if( a && a.b && a.b.c && !a.b.c.d){ /* ... */ }

You can remove checks on the left side of the checks if you are sure those exist. E.g.: If you know that a.b always exist, you can simplefy:

if( a.b.c && !a.b.c.d){ /* ... */ }
Martijn
  • 15,791
  • 4
  • 36
  • 68
0

If you really want to make sure the complete property chain is not undefined you have to check every single step and the later ones won't be executed if at least && condition is false.

if (data3 && data3.fields && data3.fields[i+2] && data3.fields[i+2].values && data3.fields[i+2].values.value && data3.fields[i + 2].values.value[0]) {
  data3.fields[i + 2].values.value[0] = "";
} else {
  break;
}

Another way would be to just do it and catch the exception:

try {
  data3.fields[i + 2].values.value[0] = "";
} catch (e) {
  break;
}
Sebastian Speitel
  • 7,166
  • 2
  • 19
  • 38
0

The error is telling you that data3.fields[i+2].values is undefined. You can't check for a property .value on undefined.

You'd need to verify each property/index belongs along the way if you always want that nested path to default to an empty string.

if (data3.fields[i+2] === undefined) {
  data.fields[i+2] = {};
}

if (data3.fields[i+2].values === undefined) {
  data3.fields[i+2].values = {};
}

if (data3.fields[i+2].values.value === undefined) {
  data3.fields[i+2].values.value = [];
}

// and finally your empty string assignment
if (data3.fields[i+2].values.value[0] === undefined) {
  data3.fields[i+2].values.value[0] = '';
}

Depending on your requirements, you might be able to get away with assigning a stub as soon as you know data3.fields[i+2] is undefined.

if (data3.fields[i+2] === undefined) {
  data3.fields[i+2] = {
    values: {
      value: ['']
    }
  };
}
deefour
  • 34,974
  • 7
  • 97
  • 90
  • what if any of those are `null`? – Liam Jun 22 '18 at 14:51
  • If you needed to accommodate null, the conditions would be made less restrictive. In OPs question, `data3.fields[i+2]` is `undefined`, not null, so everything following that would be too. Consider using something like lodash's [isNil](https://lodash.com/docs/4.17.10#isNil) – deefour Jun 22 '18 at 14:53
  • If you just replace `if (data3.fields[i+2] === undefined)` with `if (data3.fields[i+2])` it will cater for both – Liam Jun 22 '18 at 14:57
  • I think you mean `! data3.fields[i+2]`, but such a change would also catch `false`, `''`, `0`, etc... – deefour Jun 22 '18 at 14:59