React-native-calendars: markedDates and selected not working

Created on 2 Jul 2018  路  9Comments  路  Source: wix/react-native-calendars

Description

When I click on a day, I need to select a day modifying state and markedDates. The state is modified but the day is not highlighted on the calendar.

Expected Behavior

The pressed day is highlighted

Observed Behavior

The pressed day is NOT highlighted

Environment

[email protected]
[email protected]

Reproducible Demo

<Calendar
      theme={{
          backgroundColor: '#ffffff',
          calendarBackground: '#ffffff',
          textSectionTitleColor: '#b6c1cd',
          selectedDayBackgroundColor: '#00adf5',
          selectedDayTextColor: '#ffffff',
          todayTextColor: '#00adf5',
          dayTextColor: '#2d4150',
          textDisabledColor: '#d9e1e8',
          dotColor: '#00adf5',
          selectedDotColor: '#ffffff',
          //arrowColor: 'orange',
          //monthTextColor: 'blue',
          //textDayFontFamily: 'monospace',
          //textMonthFontFamily: 'monospace',
          //textDayHeaderFontFamily: 'monospace',
          textMonthFontWeight: 'bold',
          textDayFontSize: 16,
          textMonthFontSize: 16,
          textDayHeaderFontSize: 16
      }}
      current = {(this.state.selected_date) || this.state.min_date}
      minDate={this.state.min_date}
      maxDate={this.state.max_date}
      onDayPress={(day) => this.onChangeDate(day)}
      markedDates={this.state.markedDates}
      monthFormat={'MMMM yyyy'}
      onMonthChange={(month) => {log('month changed', month)}}
      hideExtraDays={true}
      firstDay={1}
 />

This is the onChangeDate function:

onChangeDate(day) {
    dateSearched = this._searchDay(day);

    var newMarkedDates = this.state.markedDates;
    Object.keys(newMarkedDates).forEach(function(key) {
        delete newMarkedDates[key].selected;
    });

    newMarkedDates[dateSearched.selected_date.format("YYYY-MM-DD"].selected = true;

    this.setState(prevState => ({
        selected_date: day,
        markedDates: newMarkedDates
    }));
}

If I log "newMarkedDates", I get the correct object with the pressed day with "selected=true" property, but still the Calendar does not highlight the day.

Most helpful comment

I don't know if is the best solution but works for me.

<CalendarList {...} markedDates={{ ...this.state.markedDates, [this.state.selected_date]: { selected: true, disableTouchEvent: true, } }} />

All 9 comments

same problem

I don't know if is the best solution but works for me.

<CalendarList {...} markedDates={{ ...this.state.markedDates, [this.state.selected_date]: { selected: true, disableTouchEvent: true, } }} />

someone buy this guy a beer @ismavg55, why this is not documented?

Simples solution:
On your calendar add

      onDayPress={(day) => this.setMarkedDates(day.dateString)}
      markedDates={this.state.markedDates}

then new method in component

setMarkedDates(key) {
    let markedDates = {};
    if (typeof this.state.markedDates[key] !== 'undefined') {
      markedDates = {[key]: {selected: !this.state.markedDates[key].selected}};
    } else {
      markedDates = {[key]: {selected: true}};
    }

    this.setState((prevState) => {
      return {...prevState, markedDates};
    })
  }

Its a little workaround but it works as expected. In setMarkedDates you can save last clicked day

@kamwoz: Your solution doesnt support multi-dot

    this.state = {
      markedDates: {
        '2018-10-25': {dots: [vacation, massage, workout], selected: true, selectedColor: 'red'},
        '2018-10-26': {dots: [massage, workout], disabled: true},
      }
    }

Instead can try my solution which supports multi-dot

onDayPress={({ dateString }) => {
  const dateObj = _.cloneDeep(this.state.date);
  Object.entries(dateObj).forEach(x => x[1].selected = false);
  const obj = Object.entries(dateObj).find(x => x[0] === dateString) || [dateString, { }];
  obj[1].selected = true;

  this.setState({ date: { ...dateObj, [obj[0]]: { ...obj[1] }  }});
}}

Just thought will add a piece of additional info that might help in some situations. When I tried to update markedDates when scrolling I found that days in the months other than prev, current, next were not rendered. ie the months were blank. ("react-native-calendars": "^1.21.0")

Calling this.setState directly in the onVisibleMonthsChange callback did not work.
Had to be offloaded in setImmediate or setTimeout

state = {
    markedDates: {}
}

updateMarked = (months) => {
    //console.log('now these months are visible', months);
    let marked = {};
    months.map(month => {
        marked[month.dateString] = {selected: true, color: 'green', textColor: 'white'}
    })
    console.log(marked);
    //setTimeout(this.setState.bind(this, {markedDates: marked}), 200);
    setImmediate(this.setState.bind(this, {markedDates: marked}));

    // +++ WORKS +++
    // 1. setTimeout(this.setState.bind(this, {markedDates: marked}), 200);
    // 2. setTimeout(()=> {
    //     this.setState({markedDates: marked});
    // }, 200);
    // 3. setImmediate(this.setState.bind(this, {markedDates: marked}));

    // --- DOES NOT WORK ---
    // 1. this.setState({markedDates: marked})
    // 2. setTimeout(this.setState, 500, {markedDates: marked});

}

render = () => {
    return (
        <View>
            <CalendarList
                // Callback which gets executed when visible months change in scroll view.
                onVisibleMonthsChange={this.updateMarked}
                // Max amount of months allowed to scroll to the past. Default = 50
                pastScrollRange={12}
                // Max amount of months allowed to scroll to the future. Default = 50
                futureScrollRange={12}
                // Enable or disable scrolling of calendar list
                scrollEnabled={true}
                // Enable or disable vertical scroll indicator. Default = false
                showScrollIndicator={true}

                markedDates={this.state.markedDates}
                markingType={'period'}
            />
        </View>

    );

}

I don't know if is the best solution but works for me.

<CalendarList {...} markedDates={{ ...this.state.markedDates, [this.state.selected_date]: { selected: true, disableTouchEvent: true, } }} />

But the dot in day don't show.

Do you still have a problem?

Bellow code help if you have marked the date with multi dots or use custom market.

<Calendar
       onDayPress={onDayPress}
       markedDates={{
                    ...markedDates,
                    [selected]: {
                        selected: true,
                        disableTouchEvent: true,
                        ...markedDates.hasOwnProperty(selected) ? markedDates[selected] : {},
                    }
         }} 
/>

const onDayPress = day => { setSelected(day.dateString); };

Ref Video

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sonnguyenit picture sonnguyenit  路  3Comments

srichallamalla935 picture srichallamalla935  路  4Comments

microwin168 picture microwin168  路  4Comments

akhilsanker picture akhilsanker  路  4Comments

filippoitaliano picture filippoitaliano  路  3Comments