The question is simple, but yet I cannot figure this one out; I need to render a date-selection module, that displays the first_possible_date
and the 6 next days, and the ability to navigate back and forth until the last_possible_date
has been reached. Every date after the last_possible_date
that is rendered needs to be disabled. Navigating back is not possible if it precedes the first_possible_date
and navigating forth is not possible if it exceeds the last_possible_date
.
The data I am working with is object that has days of the week as its children, like so:
{
"1": { "name": "Monday", "categories": [5] },
"1": { "name": "Tuesday", "categories": [5] },
"1": { "name": "Wednesday", "categories": [5] },
"1": { "name": "Thursday", "categories": [5] },
"1": { "name": "Friday", "categories": [5] }
}
This data is passed, along with the first_possible_date
and last_possible_date
to my component via the props. In the componentDidMount function, I set the data to the state, like so:
this.setState({
data: this.props.data
}, () => {
this.getFormattedDates(this.props.firstpossible);
});
In the getFormattedDates
function, I set this data in a local variable, using the immutability React mentions in their tutorial application, preserving the data in this.state.data
, like so:
let dates = Object.assign({}. this.state.data);
The categories variables contain some information I need to render some components (or not) in my UI. But as you can see, this array does not contain all days yet, so I need to add them. For this I have an array of days, and check if the iterated day of the week is in my data-array, like so:
// //Add saturday and sunday to the array, as well as add additional data
for (var i = 0; i < daysoftheweek.length; i++) {
let datefound = false;
let dayoftheweekindex = i * 1 + 1;
let j = (Object.keys(dates).length === 7) ? 0 : 1;
let limit = (Object.keys(dates).length === 7) ? 6 : 5;
for (j; j <= limit; j++) {
if (daysoftheweek[i].toLowerCase() === dates[j].name.toLowerCase()) {
dates[j]['dayoftheweek'] = dayoftheweekindex;
dates[j]['name'] = dates[j]['name'].toLowerCase();
datefound = true;
}
}
if (!datefound) {
let newindex = dayoftheweekindex - 1;
dayoftheweekindex = (dayoftheweekindex === 7) ? 0 : dayoftheweekindex;
dates[dayoftheweekindex] = {
name: daysoftheweek[newindex],
categories: [],
dayoftheweek: dayoftheweekindex
};
}
}
When this is done, I want to shift the array, so that the first_possible_date
is the first in the array, so it's easier to (re-)render my date selection, like so:
// Shift the array, so the first element is the day after the first possible transport date.
let shiftedDates = [];
let firstPossible = startdate.getDay();
for (var i = 0; i < Object.keys(dates).length; i++) {
let date = dates[i];
if (date.dayoftheweek < firstPossible) {
shiftedDates.splice(shiftedDates.length, 0, dates[i]);
} else {
shiftedDates.splice(i - firstPossible, 0, dates[i]);
}
}
Lastly, I add some extra data, empty the categories
variable if the date exceeds the last_possible_date
(I disable the buttons if the categories array is empty), and return the data in a 4 / 3 object to be rendered, like so:
//Finally, add some more data to every shifted element, so it can be used for displaying.
for (let i in shiftedDates) {
let incrementedDate = Helper.addDaysToDate(startdate, i * 1);
shiftedDates[i]['dayofthemonth'] = incrementedDate.getDate();
shiftedDates[i]['monthIndex'] = incrementedDate.getMonth();
shiftedDates[i]['month'] = months[incrementedDate.getMonth()];
shiftedDates[i]['year'] = incrementedDate.getFullYear();
let lastPossibleDate = this.props.lastpossible;
if (shiftedDates[i].monthIndex > lastPossibleDate.getMonth() || (shiftedDates[i].monthIndex === lastPossibleDate.getMonth() && shiftedDates[i].dayofthemonth > lastPossibleDate.getDate())) {
shiftedDates[i].categories = [];
}
if (true) {}
}
let formattedDates = {
0: [
shiftedDates[0],
shiftedDates[1],
shiftedDates[2],
shiftedDates[3],
],
1: [
shiftedDates[4],
shiftedDates[5],
shiftedDates[6],
]
};
this.setState({otherdates: formattedDates});
Navigating back and forth, I add, or remove days to the startdate
as I go along, like so:
let startdate = this.state.startdate;
if (moveahead) {
let startDateBuffer = Helper.addDaysToDate(startdate, 7);
if (startDateBuffer < this.props.lastpossible) {
this.hideAll();
startdate = Helper.addDaysToDate(startdate, 7);
}
} else {
if (this.props.firstpossible < startdate) {
this.hideAll();
startdate = Helper.addDaysToDate(startdate, -7);
}
}
this.getFormattedDates(startdate);
It all works fine, even though the code may be messy, but there's a problem I need to fix.
You see, even though I created a variable from the data in this.state.data
, it is still mutated, when I modify my local created variable let dates
. What's even more weird, is that logging the this.state.data
the first time results in the data already being modified. In between the creation of the let dates
variable and the loop to add saturday and sunday to the array, I placed a log console.log(this.state.data);
which shows me, even at the first iteration, that saturday, and sunday have been added, while the code below to add them has never been executed at that point (it is executed after the log). The resulting JSON looks like:
{
"0": { "name": "sunday", "categories": [0], "dayoftheweek": 7, "dayofthemonth": 9, "monthIndex": 8, "month": "september", "year": 2018 },
"1": { "name": "monday", "categories": [5], "dayoftheweek": 1, "dayofthemonth": 10, "monthIndex": 8, "month": "september", "year": 2018 },
"2": { "name": "tuesday", "categories": [5], "dayoftheweek": 2, "dayofthemonth": 4, "monthIndex": 8, "month": "september", "year": 2018 },
"3": { "name": "wednesday", "categories": [5], "dayoftheweek": 3, "dayofthemonth": 5, "monthIndex": 8, "month": "september", "year": 2018 },
"4": { "name": "thursday", "categories": [5], "dayoftheweek": 4, "dayofthemonth": 6, "monthIndex": 8, "month": "september", "year": 2018 },
"5": { "name": "friday", "categories": [5], "dayoftheweek": 5, "dayofthemonth": 7, "monthIndex": 8, "month": "september", "year": 2018 },
"6": { "name": "saturday", "categories": [0], "dayoftheweek": 6, "dayofthemonth": 8, "monthIndex": 8, "month": "september", "year": 2018 }
}
When the code is executed that modifies the categories
variables if the current iterated date is beyond the last_possible_date
, it properly empties the categories and disables the buttons in the UI, as expected. But, when you then navigate back again, they are still disabled, because the categories array stays empty. Logging the this.state.data
again reveals that the data has changed, with empty categories
arrays in some days.
So, tl;dr...
- Creation of variable from state data, rendering state data immutable
- Modification of variable
- Modifications to variable also modify state data
- (Optional) Modifications to variable are after logging, but still logs reflect changes on the first iteration.