0

I have an object with the numerical months as the keys for other objects, containing years for keys and Zeros for the initial values.

MonthRow : {   
   1 : {2017:0,2018:0},
   2 : {2017:0,2018:0},
   3 : {2017:0,2018:0},
   4 : {2017:0,2018:0},
   5 : {2017:0,2018:0},
   6 : {2017:0,2018:0}
}

After a query I am using the following code to set the values for each of these objects

 Object.keys(MainData.MonthRow).forEach(function(key){
    MainData.block.forEach(function(element,i,block){
      if(key == element.month){
        MainData.year.forEach(function(year, j, years){
          if(element.year == year && key == element.month){
           console.log("This is the Sale: ", element.Sale, "This is the year ", year, key);
            console.log(MainData.MonthRow[key], "This is the Month Key");
            console.log(MainData.MonthRow[key][year], "This is the year and key");
            MainData.MonthRow[key][year]=element.Sale;
            console.log(MainData.MonthRow)
          }
        })   
      }
    });

But after assigning the value using MonthRow[key][year]=element.Sale; it assigns the value to all the months.

My punctual question is how can I assign a value to obj.key.year = value where key and year is a variable?

Recreated the in JSFiddle got the expected result, but on Sails frame work its not working

JSFiddle Test

enter image description here

bleik urrego
  • 90
  • 10
  • What is the difference between `MainData.MonthRow` and `MonthRow`? Which is the object shown at the top of your question? Could you please provide a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – Phil Oct 18 '18 at 22:26
  • You're using variables as object keys properly. `object[key][year]` would work, but only if `object[key]` already exists. – zfrisch Oct 18 '18 at 22:27
  • @Phil MainData.MonthRow and MonthRow are the same. I've tried using MainData.MonthRow[key][year] = element.Sale; But I still get all back all the months assign the last value of the iteration – bleik urrego Oct 18 '18 at 22:35
  • Sorry, that doesn't make sense. In your question, you have both `MainData.MonthRow` and `MonthRow`. Where do you assign `MonthRow`? Are you having trouble producing a **Minimal, Complete and Verifiable example**? – Phil Oct 18 '18 at 22:37
  • Also, what is `MainData.block.`. Please, please please consider Phil's initial comment to you. Read the link. – Randy Casburn Oct 18 '18 at 22:40
  • This seems like a reference error, you've probably used the same object to initialise all the months in `MonthRow`. BTW, the code could be shorter as you don't need to loop `MonthRow`. – ibrahim mahrir Oct 18 '18 at 22:42
  • I tried reproducing this as best I could with the little information provided but could not see any problems ~ [JSFiddle reproduction](http://jsfiddle.net/philbrown/kojueb2g/5/) – Phil Oct 18 '18 at 22:45
  • @phil Thanks for the working example. I've updated the question – bleik urrego Oct 18 '18 at 23:21
  • How are you initializing the `MonthRow` object? I bet there are some messed up references there. – ibrahim mahrir Oct 18 '18 at 23:24
  • @Phil but those aren't images of code / data. They are images of console logs, which are fine. – ibrahim mahrir Oct 18 '18 at 23:39
  • I don't see anything like that in my console – Phil Oct 18 '18 at 23:55
  • @ibrahimmahrir - The whole process is based on a couple of promises. The first gets the data from the DB, then creates the array MonthRow, then iterates through the block to assign the MonthRow value. I am creating the MonthRow like so MonthRow = {'1' : MainData.years, ...} and Im printing the object before I assign it to ensure the key does exist. – bleik urrego Oct 19 '18 at 01:12

1 Answers1

3

The problem is that all sub-objects inside MonthRow are referencing the same object (MainData.years), in other words MainData.years === MonthRow['1'] === MonthRow['2'] === .... So changes to one of those sub-objects will get reflected on all sub-objects, on MainData.years too. Here's a demonstration of the problem:

var objA = {};

var objB = objA;            // objA is not copied to objB, only a reference is copied
                            // objA and objB are pointing/referencing the same object

objB.foo = "bar";           // changes to one of them ...

console.log(objA);          // ... are reflected on the other

To fix this, you need to clone the object MainData.years before assigning to each property of the object MonthRow, thus the sub-objects will all be different objects. You can use Object.assign for that like so:

MonthRow = {
  '1': Object.assign({}, MainData.years),
  '2': Object.assign({}, MainData.years),
  ...
}

Side note:

The code in the question can be refactored to a shorter one as you don't need to loop over the keys of MonthRow nor MainData.year, you only need to loop MainData.block, and for each element, you just check if the current element's year is included in MainData.year (using either indexOf or includes), and then update MainData.MonthRow using the element's year and month:

MainData.block.forEach(function(element) {
  if(MainData.year.indexOf(element.year) !== -1) {
    MainData.MonthRow[element.month][element.year] = element.sale;
  }
});
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73