1

Original problem:

I'm trying to create a new object, but the insert is a bit complex:

I am generating an object inside an object.

result = Object.values(window.datas).reduce( (newObj, dataRow) => {
    if ( (user.user_id == dataRow.user_id) && (that.dataResult[dataRow.data_id] !== undefined) && (that.dataResult[dataRow.data_id].length !== 0) ) {
        newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].name][that.dataResult[dataRow.data_id].ts] = that.dataResult[dataRow.data_id];
    }
    return newObj;
}, {} );

I get this error:

Error in v-on handler: "TypeError: Cannot set property '2017-02-01' of undefined"

on the line:

newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].name][that.dataResult[dataRow.data_id].ts] = that.dataResult[dataRow.data_id];

What I tried:

  1. When changing this row (to an unwanted result, but just for testing) to have only one key object (instead of 2), and it works:

newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].name] = that.dataResult[dataRow.data_id];

  1. I tried doing something like this - Adding a temp variable and pushing to it the results, at the beginning i thought i solved the problem, but after reviewing this a few times i noticed that the results are getting duplicated and "cat_id"s are getting duplicated.

result = Object.values(window.datas).reduce( (newObj, dataRow) => {
    if ( (user.user_id == dataRow.user_id) && (that.dataResult[dataRow.data_id] !== undefined) && (that.dataResult[dataRow.data_id].length !== 0) ) {

        temp[that.dataResult[dataRow.data_id].ts] = that.dataResult[dataRow.data_id];
        newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].app_name] = temp;
    }
    return newObj;

}, {} );
temp = {};

Main question:

What is the right way to set an object variable in this way:

objectVariable[step1][step2] = result; 

Full code:

let that    = this;
let result  = null;
let temp    = {};

this.activeUsers.forEach( user => {

    result = Object.values(window.datas).reduce( (newObj, dataRow) => {
        if ( (user.user_id == dataRow.user_id) && (that.dataResult[dataRow.data_id] !== undefined) && (that.dataResult[dataRow.data_id].length !== 0) ) {
            newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].app_name][that.dataResult[dataRow.data_id].ts] = that.dataResult[dataRow.data_id];
        }
        return newObj;
    }, {} );


    if (Object.entries(result).length !== 0) {
        that.usersToDatas[user.user_id] = result;
    }

    temp = {};
});
wellhellothere
  • 539
  • 1
  • 4
  • 10
  • 1
    Can you please add a sample of `window.datas` so we can see the data structure? Trying to figure it out by reading these long statements is annoying. Do you have control over how window.datas is structured? Since judging from the code, it's likely that if the datas would be an array, the code becomes easier and shorter. – Shilly Apr 15 '19 at 13:52
  • @Shilly it's funny that you say that, because my previous post discussed that, and decided to actually use objects: https://stackoverflow.com/questions/55683780/what-is-the-meaning-of-127-2171-empty-x-2170-in-the-console-log – wellhellothere Apr 15 '19 at 13:56
  • A JSON.stringify()'ed sample of the first 10 or 20 object keys will suffice. No need to post all 2k+. – Shilly Apr 15 '19 at 13:58

4 Answers4

2

Since ECMAScript 2015 (ES6), you can declare an object with computed property names:

const step1 = 'firstStep', step2 = 'secondStep';

let obj = {
  [step1]: {
    [step2]: 'value'
  }
};

console.log(obj[step1][step2]);

Within a loop and object destructuring:

const steps = [
  ['loopA', 'loopA_step1', 'loopA_step2', 'loopA_value'],
  ['loopB', 'loopB_step1', 'loopB_step2', 'loopB_value']
];

let obj = {
  'defaultKeyA': 'defaultValueA', // These pairs will be added in the object each
  'defaultKeyB': 'defautlValueB'  // time the loop will be done, into "loopX".
};

for (let i = 0; i < steps.length; i++) {
  const step = steps[i];
  
  // Creates the key "loopX".
  obj[step[0]] = {
    // Inserts original "obj" content into the new object.
    ...obj,
    
    // Creates the key "loopX_step1" with an object as value.
    [step[1]]: {
      // Creates the key "loopX_step2" with "loopX_value" as value.
      [step[2]]: step[3]
    }
  };
}

console.log(obj);
Kévin Bibollet
  • 3,573
  • 1
  • 15
  • 33
  • This seems right, but since it's in a loop, and I have to add items to that same array (append to "step1" and to "step2"). Can you please refer to that issue in your comment too? I tried doing this in a few variations with the object spread operator `{...}` and i got weird results. – wellhellothere Apr 16 '19 at 06:38
  • This is my last try: `newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].name] = { ...newObj, [that.dataResult[dataRow.data_id].ts] : {[dataRow.data_id] : that.dataResult[dataRow.data_id]}}` – wellhellothere Apr 16 '19 at 06:46
  • I edited my answer including an example with a loop and destructuring, but I am not sure it will really help because I don't know what all your object properties look like. Can you provide some samples? Or maybe give a clearer snippet? – Kévin Bibollet Apr 16 '19 at 07:24
0

You can use hasOwnProperty function to see if an object has a property.

for exemple

let myObject = {};
let prop = "myProperty";
let prop 2 = "mySecondProperty"

if(!myObject.hasOwnProperty(prop)){
   myObject[prop] = {};
}

myObject[prop][prop2] = ....

you can use it in your loop and set "default" value if "myObject[prop]" is not defined

Maxime Girou
  • 1,511
  • 2
  • 16
  • 32
0

You can do (objectVariable[step1] = objectVariable[step1] || {})

var objectVariable = {};
var step1 = 'a';
var step2 = 'b';

var result = 'hello world';

(objectVariable[step1] = objectVariable[step1] || {})[step2] = result;

console.log(objectVariable)
Taki
  • 17,320
  • 4
  • 26
  • 47
0

Regarding objectVariable[step1][step2] = result, you can use Object.assign plus computed properties, like:

const myObj = { someProp: "someValue" };
const foo = "propertyFoo";
const bar = "propertyBar";
Object.assign(myObj, { [foo]: { [bar]: "baz" } });
console.log(myObj);
(In general, though, and on a tangent note, lines like
newObj[that.catToApp[that.dataResult[dataRow.data_id].cat_id].app_name][that.dataResult[dataRow.data_id].ts] = that.dataResult[dataRow.data_id];

are just scary.)

mbojko
  • 13,503
  • 1
  • 16
  • 26