0

Sorry for the strange title, but I've come across an issue that is plain weird. To give some background, i'm working on a booking system that takes a time range as an input from admin, generates available times based on it, and then reduces the available times based on already made bookings (i.e admin specifies availability from 10:00 to 12:00, booking has been made to 11:30, available times will be times = [10:00, 10:30, 11:00, 12:00]).

I have an object that contains per month for each day the available times.

availableTimesPerDay: {
    1: ["10:00","10:30","11:00","11:30","12:00"],
    2: ["10:00","10:30","11:00","11:30","12:00"],
    3: ["10:00","10:30","11:00","11:30","12:00"],
    ....
}

Where the number represents the date for the given month.

Bookings are represented as an array of objects, format is:

bookedTimes = [
    {
        date: "2022-12-01T11:30:00.000+02:00"
    }
];

I planned to have a function which would iterate through each booking and remove the availability for that time on a given date (based on example above, 11:30 would need to be removed from availableTimesPerDay[1] leaving the value for it as ["10:00","10:30","11:00","12:00"]

The function itself is defined as such:

function reduceAvailableTimesBasedOnDateTime(availableTimesPerDay,bookedTimes){
    console.log(JSON.stringify(availableTimesPerDay));
    bookedTimes.forEach((bookedDateObject) => {
        let bookedDate = new Date(bookedDateObject.date); 
        // 1
        let currentAvailableTimesOnDate = availableTimesPerDay[bookedDate.getDate()];
        // ["10:00","10:30","11:00","11:30","12:00"]
        let bookedTime = bookedDate.toLocaleTimeString('et');
        // "13:30:00"
        let time = bookedTime.substring(0,bookedTime.length - 3);
        // "13:30"
        let index = currentAvailableTimesOnDate.indexOf(time);
        // 3
        if (index > -1) { 
            currentAvailableTimesOnDate.splice(index, 1);
            // ["10:00","10:30","11:00","12:00"]
        }
    })
    console.log(JSON.stringify(availableTimesPerDay));
    return availableTimesPerDay;
}

The way I understand this function is that i've extracted a specific array of available times into a new variable and removed a specific time from that array. I have done no modifications on an original data and I would expect at this stage the availableTimesPerDay to remain unmodified. However, when I run my code, the availableTimesPerDay is modified even though I do no operations with availableTimesPerDay object itself.

What's even stranger is that the modification is not just strictly done on the 1st element, but on all specific dates that have the same day of the week. Here's output from the console for the console.log(availableTimesPerDay) defined in the function (note that 11:30 value is removed on dates 1st of December, 8th of December, 15th of December etc.

booking-helper.js:94 {"1":["10:00","10:30","11:00","11:30","12:00"],"2":[],"3":[],"4":[],"5":[],"6":[],"7":[],"8":["10:00","10:30","11:00","11:30","12:00"],"9":[],"10":[],"11":[],"12":[],"13":[],"14":[],"15":["10:00","10:30","11:00","11:30","12:00"],"16":[],"17":[],"18":[],"19":[],"20":[],"21":[],"22":["10:00","10:30","11:00","11:30","12:00"],"23":[],"24":[],"25":[],"26":[],"27":[],"28":[],"29":["10:00","10:30","11:00","11:30","12:00"],"30":[],"31":[]}
booking-helper.js:105 {"1":["10:00","10:30","11:00","12:00"],"2":[],"3":[],"4":[],"5":[],"6":[],"7":[],"8":["10:00","10:30","11:00","12:00"],"9":[],"10":[],"11":[],"12":[],"13":[],"14":[],"15":["10:00","10:30","11:00","12:00"],"16":[],"17":[],"18":[],"19":[],"20":[],"21":[],"22":["10:00","10:30","11:00","12:00"],"23":[],"24":[],"25":[],"26":[],"27":[],"28":[],"29":["10:00","10:30","11:00","12:00"],"30":[],"31":[

What's even more interesting is that if I copy the same function to codepen with same data or call it directly from the browsers console it works as expected - it removes the specific time from a specific date.

Banana
  • 814
  • 1
  • 8
  • 28

2 Answers2

3

The way I understand this function is that I've extracted a specific array of available times into a new variable and removed a specific time from that array. I have done no modifications on an original data and I would expect at this stage the availableTimesPerDay to remain unmodified.

But that's not what is happening. A mere assignment of an array to a new variable does not create a new array. The new variable will reference the same array. So whatever mutation you bring to that array will be visible whether you look at that array via currentAvailableTimesOnDate or via availableTimesPerDay[bookedDate.getDate()]: they are just different ways to see the same array object.

If you don't want that splice to affect availableTimesPerDay[bookedDate.getDate()], then you must take a copy:

let currentAvailableTimesOnDate = [...availableTimesPerDay[bookedDate.getDate()]];

What's even stranger is that the modification is not just strictly done on the 1st element, but on all specific dates that have the same day of the week.

This would suggest that you have initialise availableTimesPerDay with a similar misunderstanding, so that all entries in that array reference the same array. This could for instance happen when you had initialised it as follows:

let availableTimesPerDay = Array(7).fill( ["10:00","10:30","11:00","11:30","12:00"]);

This creates one array ["10:00","10:30","11:00","11:30","12:00"] and populates the outer array with duplicate references to that array.

You should solve that too, and do something like this:

let availableTimesPerDay = Array.from({length: 7}, () => 
     ["10:00","10:30","11:00","11:30","12:00"]
);

Now that array literal is evaluated 7 times, each time producing a new array.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thanks a lot. I sort of guessed that it's most likely to do something with how JS manages the arrays, but couldn't figure out exactly what I need to do in order to fix it. Now it works as intended. It's very strange that it did work when I called it out directly from console or when I copied it to codepen. – Banana Dec 04 '22 at 15:57
  • 1
    See also addition to answer. Maybe that is also an issue you could have, but I'm only guessing as you did not provide that part of your code. – trincot Dec 04 '22 at 15:59
0

It seems like you might be under the mistaken assumption that this code:

let currentAvailableTimesOnDate = availableTimesPerDay[bookedDate.getDate()];

makes a copy of the array and you are then operating on the copy, not the original array. But that's not the case. You're essentially just aliasing the same array and then operating on it. To demonstrate:

const availableTimesPerDay = {
    1: ["10:00","10:30","11:00","11:30","12:00"],
    2: ["10:00","10:30","11:00","11:30","12:00"],
    3: ["10:00","10:30","11:00","11:30","12:00"],
};

const currentAvailableTimesOnDate = availableTimesPerDay[1];
currentAvailableTimesOnDate.splice(0, 100);

console.log(availableTimesPerDay[1]);

If you run this code in the browser console, it will log an empty array, even though you "do no operations with availableTimesPerDay object itself."

To copy the array, you have at least a few options:

const currentAvailableTimesOnDate = availableTimesPerDay[1].slice();
// OR
const currentAvailableTimesOnDate = [...availableTimesPerDay[1]];
// OR
const currentAvailableTimesOnDate = Array.from(availableTimesPerDay[1]);

Using any of the above code, you would then be operating on a copy of the array, not the original one.

Regarding the day-of-week thing, that sounds to me like you are using getDay() instead of getDate() somewhere, though I do not see that in your code, and in fact you say you do not see that in the browser console. I don't have a clear answer for that but could it be that at one point you had getDay() and you are accidentally running an older version of the code that is different from what you are showing here and testing in the console?

Aurast
  • 3,189
  • 15
  • 24
  • 1
    In regards to 'day-of-week' thing, it appears to be fixed now, I suppose JS handles these as copies as well (from the part where I generate it) and when one got changed, it changed all of them. – Banana Dec 04 '22 at 16:00