React-native-calendars: How to call scrollToDay() method to set the today's day in Agenda View?

Created on 22 May 2017  路  10Comments  路  Source: wix/react-native-calendars

Hi,

I am very new to React native and working on Calendar App. I really like this calendar Agenda view.
I want to set the today's date on button click in Agenda view or move to a different month -
https://hub.mangoapps.com/sf/ODcxNzZfMTMyNzE0NQ .

Is it possible to set the date?

Most helpful comment

Hi,
Here is how I've fixed the issue..

Agenda control is declared like this ->
..
/>

Today button placed like this in view and calling method _pressToday()

_pressToday(event) {
const today = new Date();
this.agenda.chooseDay(today);
}

Hope this will solve your issue.

All 10 comments

Try this code:

<Agenda ref={(agenda) => { this.agenda = agenda; }} />

Then in your 'today' handler method:

this.agenda.chooseDay(date)

Tell me if this works to you. I probably will add chooseDay to documentation soon

Hi Tautvilas,

Thank you for prompt response.

I've tried above solution but getting error "undefined is not an object (evaluating 'this.agenda.chooseDay')" - https://dongawli.tinytake.com/sf/MTYyNzk4NV81NTA4Mzgz

Do I need to import any component/class/file from React Native Calendars package ?
Currently I've just imported {Agenda} from 'react-native-calendars'.

Are you sure you got the reference code right?

https://facebook.github.io/react/docs/refs-and-the-dom.html

Also references are only accesible after component is mounted

Yes, I am using the reference code right.
Even I am not able to use the 'this.state.items', timeToString() method in newly added handler methods.
Same methods or state variables I am able to access from loadItems() method. There is something not right in my project may be. I am finding out.

Please let me know is it necessary to register the component
Navigation.registerComponent('Agenda', () => AgendaScreen); as I am not using registerScreens() in my project and directly accessing agenda.js

This is example how you should achieve what you want. There was also one bug that I fixed just now to make chooseDay properly work.

import React, {Component} from 'react';
import {
  Text,
  TouchableOpacity,
  View,
  Dimensions,
  Animated
} from 'react-native';
import XDate from 'xdate';

import {parseDate, xdateToData} from '../interface';
import dateutils from '../dateutils';
import CalendarList from '../calendar-list';
import ReservationsList from './reservation-list';
import styleConstructor from './style';

const CALENDAR_OFFSET = 38;

export default class AgendaView extends Component {

  constructor(props) {
    super(props);
    this.styles = styleConstructor(props.theme);
    this.screenHeight = Dimensions.get('window').height;
    this.scrollTimeout = undefined;
    this.state = {
      openAnimation: new Animated.Value(0),
      calendarScrollable: false,
      firstResevationLoad: false,
      selectedDay: parseDate(this.props.selected) || XDate(true),
      topDay: parseDate(this.props.selected) || XDate(true),
    };
    this.currentMonth = this.state.selectedDay.clone();
    this.expandCalendar = this.expandCalendar.bind(this);
  }

  onLayout(event) {
    this.screenHeight = event.nativeEvent.layout.height;
    this.calendar.scrollToDay(this.state.selectedDay.clone(), CALENDAR_OFFSET, false);
  }

  onVisibleMonthsChange(months) {
    if (this.props.items && !this.state.firstResevationLoad) {
      clearTimeout(this.scrollTimeout);
      this.scrollTimeout = setTimeout(() => {
        if (this.props.loadItemsForMonth) {
          this.props.loadItemsForMonth(months[0]);
        }
      }, 200);
    }
  }

  loadReservations(props) {
    if ((!props.items || !Object.keys(props.items).length) && !this.state.firstResevationLoad) {
      this.setState({
        firstResevationLoad: true
      }, () => {
        if (this.props.loadItemsForMonth) {
          this.props.loadItemsForMonth(xdateToData(this.state.selectedDay));
        }
      });
    }
  }

  componentWillMount() {
    this.loadReservations(this.props);
  }

  componentWillReceiveProps(props) {
    if (props.items) {
      this.setState({
        firstResevationLoad: false
      });
    } else {
      this.loadReservations(props);
    }
  }

  expandCalendar() {
    this.setState({
      calendarScrollable: true
    });
    Animated.timing(this.state.openAnimation, {
      toValue: 1,
      duration: 300
    }).start();
    this.calendar.scrollToDay(this.state.selectedDay, 100 - ((this.screenHeight / 2) - 16), true);
  }

  chooseDay(d) {
    const day = parseDate(d);
    this.setState({
      calendarScrollable: false,
      selectedDay: day.clone()
    });
    if (this.state.calendarScrollable) {
      this.setState({
        topDay: day.clone()
      });
    }
    Animated.timing(this.state.openAnimation, {
      toValue: 0,
      duration: 200
    }).start();
    this.calendar.scrollToDay(day, CALENDAR_OFFSET, true);
    if (this.props.loadItemsForMonth) {
      this.props.loadItemsForMonth(xdateToData(day));
    }
    if (this.props.onDayPress) {
      this.props.onDayPress(xdateToData(day));
    }
  }

  renderReservations() {
    return (
      <ReservationsList
        rowHasChanged={this.props.rowHasChanged}
        renderItem={this.props.renderItem}
        renderDay={this.props.renderDay}
        renderEmptyDate={this.props.renderEmptyDate}
        reservations={this.props.items}
        selectedDay={this.state.selectedDay}
        topDay={this.state.topDay}
        onDayChange={this.onDayChange.bind(this)}
        onScroll={() => {}}
        ref={(c) => this.list = c}
      />
    );
  }

  onDayChange(day) {
    const newDate = parseDate(day);
    const withAnimation = dateutils.sameMonth(newDate, this.state.selectedDay);
    this.calendar.scrollToDay(day, CALENDAR_OFFSET, withAnimation);
    this.setState({
      selectedDay: parseDate(day)
    });
  }

  render() {
    const weekDaysNames = dateutils.weekDayNames(this.props.firstDay);
    const maxCalHeight = this.screenHeight + 20;
    const calendarStyle = [this.styles.calendar, {height: this.state.openAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: [104, maxCalHeight]
    })}];
    const weekdaysStyle = [this.styles.weekdays, {opacity: this.state.openAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: [1, 0]
    })}];

    let knob = (<View style={this.styles.knobContainer}/>);

    if (!this.props.hideKnob) {
      knob = (
        <View style={this.styles.knobContainer}>
          <TouchableOpacity onPress={this.expandCalendar}>
            <View style={this.styles.knob}/>
          </TouchableOpacity>
        </View>
      );
    }

    return (
      <View onLayout={this.onLayout.bind(this)} style={[this.props.style, {flex: 1}]}>
        <View style={this.styles.reservations}>
          {this.renderReservations()}
        </View>
        <Animated.View style={calendarStyle}>
          <CalendarList
            theme={this.props.theme}
            onVisibleMonthsChange={this.onVisibleMonthsChange.bind(this)}
            ref={(c) => this.calendar = c}
            selected={[this.state.selectedDay]}
            current={this.currentMonth}
            markedDates={this.props.items}
            onDayPress={this.chooseDay.bind(this)}
            scrollingEnabled={this.state.calendarScrollable}
            hideExtraDays={this.state.calendarScrollable}
            firstDay={this.props.firstDay}
          />
          {knob}
        </Animated.View>
        <Animated.View style={weekdaysStyle}>
          {weekDaysNames.map((day) => (
            <Text key={day} style={this.styles.weekday}>{day}</Text>
          ))}
        </Animated.View>
      </View>
    );
  }
}

Thank you Tautvilas.

Able to solve the issue and set the calendar date to today.

I have the same problem, I just want selected variable in render part is today.
I used references in <Agenda />and put this.agenda.chooseDay(date) in selected variable. What is wrong?
Thank you!

Hi,
Here is how I've fixed the issue..

Agenda control is declared like this ->
..
/>

Today button placed like this in view and calling method _pressToday()

_pressToday(event) {
const today = new Date();
this.agenda.chooseDay(today);
}

Hope this will solve your issue.

Thank you about your answer, I will try the same way with your - have button "TODAY". So It's impossible to set selected variable become today, right?
@dongawli

If I scroll the agenda to the next month it doesn't go back anymore.
For example, today is Jan 7th. When I scroll down to someday in February and press the button with the following action:
this.agenda.chooseDay('2019-01-07')

It doesn't scroll back to Jan 7th.

Anyone had this issue? Thx

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joaosauer picture joaosauer  路  4Comments

dobiedad picture dobiedad  路  4Comments

idlework picture idlework  路  4Comments

MrAlekhin picture MrAlekhin  路  4Comments

henrikra picture henrikra  路  3Comments