0
const eventsByDay = {
  "17 May": [
    // some objects
  ],
  "18 May": [
    // some objects
  ],
  "19 May": [
    // some objects
  ]
};

const timeIntervals = [
  { timeStart: "10:00", timeFinish: "11:00" },
  { timeStart: "11:00", timeFinish: "12:00" },
  { timeStart: "12:00", timeFinish: "13:00" },
  { timeStart: "13:00", timeFinish: "14:00" }
];

const eventsDefaultConfig = {
  slidesPerView: "auto",
  spaceBetween: 16,
  navigation: {
    nextEl: "",
    prevEl: ""
  }
};

let eventsConfigs = {};

for (const day in eventsByDay) {
  const dayNumber = day.split(" ", 1)[0];
  timeIntervals.forEach(interval => {
    const configName = `${dayNumber}-${interval.timeStart}`;
    console.log(configName);
    eventsConfigs[configName] = eventsDefaultConfig;
    eventsConfigs[configName].navigation.nextEl = `${configName}-next-slide`;
    eventsConfigs[configName].navigation.prevEl = `${configName}-prev-slide`;
  });
}

console.log(eventsConfigs);

I'm trying to create objects with auto generated values. I'm using for...of to iterate main object (eventsByDay) and nested forEach loop to iterate array with time intervals. My goal is object that contains following structure and naming (each element in navigation object has unique name based on date from eventByDay and time interval from array)

{
    "17-10:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "17-10:00-next-slide",
            "prevEl": "17-10:00-prev-slide"
        }
    },
    "17-11:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "17-11:00-next-slide",
            "prevEl": "17-11:00-prev-slide"
        }
    },
    "17-12:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "17-12:00-next-slide",
            "prevEl": "17-12:00-prev-slide"
        }
    },
    ...
}

When I check console messages and values of configName everything seems to be good, but final result contains only object values with last value from array. What should I fix to get proper result?

{
    "17-10:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "19-13:00-next-slide",
            "prevEl": "19-13:00-prev-slide"
        }
    },
    "17-11:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "19-13:00-next-slide",
            "prevEl": "19-13:00-prev-slide"
        }
    },
    "17-12:00": {
        "slidesPerView": "auto",
        "spaceBetween": 16,
        "navigation": {
            "nextEl": "19-13:00-next-slide",
            "prevEl": "19-13:00-prev-slide"
        }
    },
    ...
}
Oleg Shchegolev
  • 176
  • 1
  • 11
  • 1
    you're working with the _same_ object on each loop iteration, because of `eventsConfigs[configName] = eventsDefaultConfig;` . You need to deep clone it or create from scratch each time. – georg May 06 '21 at 07:56
  • 2
    [Duplicate](//google.com/search?q=site%3Astackoverflow.com+js+object+copy+property+changes) of [Modifying a copy of a JavaScript object is causing the original object to change](/q/29050004/4642212). – Sebastian Simon May 06 '21 at 07:57

3 Answers3

1
eventsConfigs[configName] = eventsDefaultConfig;

You should create a deep copy here. What happens right now is that all properties of the eventsConfig object point to the same reference.

edo.n
  • 2,184
  • 12
  • 12
1

Remember, the objects are passed by reference in JS. So, when you say eventsConfigs[configName] = eventsDefaultConfig;, it is the same object you are assigning in each iteration.

All your eventsConfigs[configName] properties are pointing at a single memory location and, whatever you put there last will remain. You need to create a separate object per every eventConfig.

const eventsByDay = {
  "17 May": [
    // some objects
  ],
  "18 May": [
    // some objects
  ],
  "19 May": [
    // some objects
  ]
};

const timeIntervals = [
  { timeStart: "10:00", timeFinish: "11:00" },
  { timeStart: "11:00", timeFinish: "12:00" },
  { timeStart: "12:00", timeFinish: "13:00" },
  { timeStart: "13:00", timeFinish: "14:00" }
];

 function eventsDefaultConfig() { 
 
 return {
    slidesPerView: "auto",
    spaceBetween: 16,
    navigation: {
      nextEl: "",
      prevEl: ""
    }
  }
  
};


let eventsConfigs = {};

for (const day in eventsByDay) {
  const dayNumber = day.split(" ", 1)[0];
  timeIntervals.forEach(interval => {
    const configName = `${dayNumber}-${interval.timeStart}`;
    eventsConfigs[configName] = eventsDefaultConfig();
    eventsConfigs[configName].navigation.nextEl = `${configName}-next-slide`;
    eventsConfigs[configName].navigation.prevEl = `${configName}-prev-slide`;
  });
}

console.log(eventsConfigs);
Charlie
  • 22,886
  • 11
  • 59
  • 90
1

Because you are using the same eventsDefaultConfig object reference and overriding the value of it's properties. So you need to clone the eventsDefaultConfig object using spread operator (...) and also need to create navigation object because spread operator creates shallow copy.

Modified for loop

for (const day in eventsByDay) {
  const dayNumber = day.split(" ", 1)[0];
  timeIntervals.forEach(interval => {
    const configName = `${dayNumber}-${interval.timeStart}`;
    const navigation = {
      nextEl: `${configName}-next-slide`,
      prevEl:  `${configName}-prev-slide`
    } // create new object
    console.log(configName);
    eventsConfigs[configName] = {...eventsDefaultConfig}; //use spread operator
    eventsConfigs[configName].navigation = navigation;
  });
}

You can refer lodash js library to create deep copy object. It also provides various useful methods.

Rahul Kumar
  • 3,009
  • 2
  • 16
  • 22