5

How to get the first and last visible date in React Big Calendar? This will facilitate database queries to view events. I'm trying to call the onNavigate () function and get start and end using the moment library, but both values areundefined.

Update

I get the value of start. end only when I press the back, next arrows. How do you get these values automatically when the calendar appears?

class App extends Component {
  constructor() {
    super();
    this.state = {
      current_date: '',
      events: [{
          id: 0,
          title: 'All Day Event very long title',
          allDay: true,
          start: new Date(2019, 3, 0),
          end: new Date(2019, 3, 1),
        },
        {
          id: 1,
          title: 'Long Event',
          start: new Date(2019, 3, 7),
          end: new Date(2019, 3, 10),
        }
      ]
    };  
  }


onNavigate =(date, view) => {
  let start, end;

  if (view === 'month') {
    start = moment(date).startOf('month').startOf('week')
    console.log(start)
    end = moment(date).endOf('month').endOf('week')
  }
  console.log(start, end);

  return console.log({ start, end });
}

  render() {
    console.log(this.state.current_date)
    return (
      <div>
        <Calendar
           localizer={localizer}
            events={this.state.events}
            startAccessor="start"
            endAccessor="end"
            onNavigate={this.onNavigate()}
          />
        </div>
    );
  }
}
Umbro
  • 1,984
  • 12
  • 40
  • 99

7 Answers7

5

You made a common mistake when using arrow functions inside react components. just simply by changing onNavigate={this.onNavigate()} to onNavigate={this.onNavigate} your problem will be solved. I will give you a simple example to find out what is happening here. If you simply want to pass a function to an onClick handler you can define your function and pass it to onClick in three ways:

1- Define an arrow function and pass it:

class Example extends Component {

    clickHandler=()=>{
        console.log('I am clickHandler');
        
    }


    render() {

        return (
            <div onClick={this.clickHandler}>
                Example
            </div>
        );
    }
}

2- Define a common function and pass it:

class Example extends Component {

    clickHandler(){
        console.log('I am clickHandler');
        
    }


    render() {

        return (
            <div onClick={()=>this.clickHandler()}>
                Example
            </div>
        );
    }
}

3- Define a function and bind it (this is old and is not common anymore in ES6):

class Example extends Component {

    clickHandler(){
        console.log('I am clickHandler');
        
    }


    render() {

        return (
            <div onClick={this.clickHandler.bind(this)}>
                Example
            </div>
        );
    }
}

I hope this is helpful to you.

hydRAnger
  • 3,013
  • 3
  • 18
  • 20
Meisam Nazari
  • 904
  • 10
  • 18
  • 1
    I get the value of `start. end` only when I press the `back, next` arrows. How do you get these values automatically when the calendar appears? – Umbro Sep 06 '19 at 19:36
2

You're getting undefined because of this : onNavigate={this.onNavigate()}

This will cause this.onNavigate to be called with () ( No params ) and date will be undefined, therefore, start and end will be undefined,

You're calling the function instead of passing it

You should pass this.onNavigate either like :

onNavigate={this.onNavigate}

Or :

onNavigate={(date, view) => this.onNavigate(date, view)}

See : navigate to a specific date

Taki
  • 17,320
  • 4
  • 26
  • 47
  • I get the value of `start. end` only when I press the `back, next` arrows. How do you get these values automatically when the calendar appears? – Umbro Sep 06 '19 at 19:34
2

As you are not passing any date prop to Calendar, default date is current date. Simulate onNavigate call from your componentDidMount, like:

componentDidMount() {
    this.onNavigate(new Date(), "month");
}

BTW, onNavigate is called only back/next navigation. You would also like to handle onView, as changing from week-view to month-view will expand displayed date range.

ckedar
  • 1,859
  • 4
  • 7
  • I have to use `onView` that get view(month, week). When I get view I have to pass view to this.onNavigate() as second parametr? Can you explain it? When method `this.onView()` is call? Can you give me example? – Umbro Sep 09 '19 at 13:55
  • Well, actually you will have to keep track of the current date. I think you anyway planned for this. So you keep current date in state, initialize it with current date, pass it to Calendar as date prop and update it in onNavigate. In onView, you will recompute the displayed date range using current date in state and view type received as param. Sorry, I am not in position to create example code at this time. – ckedar Sep 09 '19 at 14:20
  • onView will get called when user changes view type - month, week, day etc. – ckedar Sep 09 '19 at 14:24
  • Complete working example: https://codesandbox.io/embed/eager-germain-hevdr – ckedar Sep 11 '19 at 08:37
2

You can get first and last visible date using this

Component:

    import dates from 'react-big-calendar/lib/utils/dates';
...
        onNavigate = (date, view, action) => {
            console.log(dates.firstVisibleDay(date), dates.lastVisibleDay(date));
        }
...
Community
  • 1
  • 1
Savaj Patel
  • 525
  • 2
  • 16
2

I was trying to apply the answers I saw here, but finally, open the source files and found a simple onRangeChange prop that returns the visible range.

onRangeChange={range => {
    console.log(range)
}}

Also, pay attention that for the Month view it returns a structure like { start, end }, but for the Week view, you will receive an array [0, ..., 6] for all the days of week. And it does not work for the Schedule view.

I didn't find how to get this range on initialization, but I believe the start date is not less than -7 days from the start of the month, and the end date is +7 days accordingly, so my solution is:

 // I use dayjs, but you can use moment or anything else
 const start = dayjs().startOf('month').subtract(7, 'day')
 const end = dayjs().endOf('month').add(7, 'day')
Ihor
  • 131
  • 1
  • 6
0

You can use this in component:

useEffect(() => {
    toolbar.onNavigate('TODAY');
}, []);

In Calendar:

onNavigate={(event, view, action) => { 
    console.log(event, view, action}); 
    // Fri Jun 11 2021 03:06:06 GMT-0300 (Brasilia Standard Time)
    // week
    // TODAY
}}
0

enter image description here

In the picture above, current day (as per this post) is 3rd of April, but if you were to ask the range it would be -
Month: { start :26th of March, end: 6th of May }
Week: { start: 2nd of April, end: 8th of April }. Actual returned value -> [sundayDate, mondayDate ..., saturdayDate] (Please note for week big calendar return array of value with 0th index representing start of the week and 6th index end of the week)
Day: { start: 3rd of April, end: 3rd of April }


Solution to get range:

use onRangeChange provided by BigCalendar for view change (Day, Week, Month) and for date navigation (Today, Back, Next).

onRangeChange={(
  range:
    | Date[]
    | {
        start: Date;
        end: Date;
      },
  view?: BigCalendar.View | undefined
) => {

  if (Array.isArray(range)) {
  //To handle week
    handleDateParameters({
      start: range[0],
      end: range[range.length - 1],
    });
  } else if (typeof range === "object" && range !== null) {
  //To handle day, month
    handleDateParameters({ start: range.start, end: range.end });
  }
}}

On initialization:

The solution is with hooks but the approach is same for class components.

Idea is to use useRef to access <Calendar /> component and mimic view click for the default view or your desired view that was set otherwise.

const calendarRef = React.useRef(null);

React.useEffect(() => {
  if (calendarRef) {
    calendarRef.current.handleViewChange("month");
  }
}, [calendarRef]);

Here we are manually triggering view change to the default view (month in our case), which in result will run onRangeChange as if you had clicked on the button manually.


<Calendar
  ref={calendarRef} //The ref that I mentioned earlier (for initialization)
  localizer={localizer}
  views={["day", "week", "month"]}
  events={calendarEventList}
  style={{ minHeight: 500 }} //Height is necessary for BigCalendar (you can also provide height to the container element)
  onView={(view) => {
    //if you want to handle view separately otherwise onRangeChange also provide view (but onRangeChange also return undefined if you click on navigation (today, back, next), so add check for that)
    if (currentView !== view) handleCurrentViewChange(view);
  }}
  onRangeChange={The one I mentioned above}
/>;

I tried explaining the best I could, if there is any mistake please do let me know. Thankyou!

Anuj Mehta
  • 383
  • 3
  • 8