React-big-calendar: custom toolbar

Created on 23 Apr 2018  路  12Comments  路  Source: jquense/react-big-calendar

Hello I was using a react-big-calendar on my project
While I was using it, I needed to do onclick on the toolbar, so I customized the toolbar
I created a class named CustomToolbar and passed the class with props, but I got the following error:

Warning: Failed prop type: You have provided a `view` prop to `Calendar` without an `onView` handler. This will render a read-only field. If the field should be mutable use `defaultView`. Otherwise, set `onView`
    in Uncontrolled(Calendar) (created by Calendar)
    in Calendar (created by Uncontrolled(Calendar))
    in Uncontrolled(Calendar) (at Calendar.js:19)
    in div (at Calendar.js:18)
    in div (at Calendar.js:17)
    in Calendar (at AssignmentSection.js:10)
    in div (at AssignmentSection.js:9)
    in AssignmentSection (at Main.js:15)
    in div (at Main.js:13)
    in Main (created by RouterContext)
    in div (at DefaultLayout.js:12)
    in DefaultLayout (created by RouterContext)
    in RouterContext (created by Router)
    in Router (at index.js:10)
    in MainProvider (at index.js:9)

How can we solve this problem?

this is my code:

import React from 'react';
import BigCalendar from 'react-big-calendar';
import Toolbar from 'react-big-calendar';
import moment from 'moment';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import '../../css/calendar.css';

BigCalendar.momentLocalizer(moment);

const Calendar = ({ state, selectDate, selectEvent }) => {
  const eventStyleGetter = (event, start, end, isSelected) => {
    return { 
      style: { backgroundColor: event.color } 
    }
  } 
  return (
    <div id="calendar-section">
      <div id="calendar-wrapper">
        <BigCalendar
          selectable
          views = {['month']}
          defaultView = "month"
          defaultDate = {new Date()}
          components = {{toolbar : CustomToolbar}}
          onSelectSlot = {selectDate}
          onSelectEvent = {selectEvent}
          eventPropGetter = {(eventStyleGetter)}
          events = {state.assignments[state.subjects[state.selectedSubject]]}
        />
      </div>
    </div>
  )
}

class CustomToolbar extends Toolbar {
  render() {
    return (
      <div className='rbc-toolbar'>
        <span className="rbc-btn-group">
          <button type="button" onClick={() => this.navigate('TODAY')} >today</button>
          <button type="button" onClick={() => this.navigate('PREV')}>back</button>
          <button type="button" onClick={() => this.navigate('NEXT')}>next</button>
        </span>
        <span className="rbc-toolbar-label">{this.props.label}</span>
      </div>
    );
  }

  navigate = action => {
    console.log(action);

    this.props.onNavigate(action)
  }
}

export default Calendar;

Most helpful comment

no need to be snarky...

@seoyunho yes provide the onView prop like you would an onChange and value prop for a controlled input, they work similarly. The calendar also has it's own moments when it wants to navigate and you should be listening for them, even with a custom toolbar.

All 12 comments

you already have a navigate function, just add the view function that it wants.

this isn't an issue, it's homework.

no need to be snarky...

@seoyunho yes provide the onView prop like you would an onChange and value prop for a controlled input, they work similarly. The calendar also has it's own moments when it wants to navigate and you should be listening for them, even with a custom toolbar.

I was able to create a custom Toolbar component by extending the default Toolbar component and overriding the render method. In order to properly import the default component I had to use the following import statement.

import Toolbar from 'react-big-calendar/lib/Toolbar';

I don't think the import statement in the OP would work. At least it didn't for me.

@jquense Can we please have a custom toolbar example put in the docs? I am getting this same error, and have searched for a while, I am fundamentally missing something. Can you provide a link to the source code where I can find an example where you provide the onView prop?

I am also having this issue. I have an onView provided to the BigCalendar component but when I pass in a custom toolbar, I start seeing this error. How can I fix it?

@jquense Any help with this one? This is what my current Calendar component looks like:

<BigCalendar
    events={this.state.events}
    date={moment(this.state.currentDate).toDate()}
    onNavigate={() => {}}
    components={
        {
           toolbar: BIToolbar({
           onMonthChange: this.onMonthChange
           }),
        }
    }
    view={defaultView}
    views={['month', 'agenda']}
    onView={() => {}}
    formats={formats}
    onSelectEvent={event => this.selectEvent(event)}
    />

Everything works fine until I added in the custom component for the toolbar. Now I keep getting this error:

error

I've also tried passed an onView to the toolbar component too but it hasn't worked. Any ideas?

The code below is working for me.

import React from 'react';
import Toolbar from 'react-big-calendar/lib/Toolbar';

export default class CalendarToolbar extends Toolbar {

    componentDidMount() {
        const view = this.props.view;
        console.log(view)
    }

    render() {
        return (
            <div>
                <div className="rbc-btn-group">
                    <button type="button" onClick={() => this.navigate('TODAY')}>today</button>
                    <button type="button" onClick={() => this.navigate('PREV')}>back</button>
                    <button type="button" onClick={() => this.navigate('NEXT')}>next</button>
                </div>
                <div className="rbc-toolbar-label">{this.props.label}</div>
                <div className="rbc-btn-group">
                    <button type="button" onClick={this.view.bind(null, 'month')}>Month</button>
                    <button type="button" onClick={this.view.bind(null, 'week')}>Week</button>
                    <button type="button" onClick={this.view.bind(null, 'day')}>Day</button>
                    <button type="button" onClick={this.view.bind(null, 'agenda')}>Agenda</button>
                </div>
            </div>
        );
    }
}

The tips is to use the onNavigate, and onView when the value change.

This is my current custom toolbar :

import React from 'react';
import PropTypes from 'prop-types';
// import styled from 'styled-components';

import { FormattedMessage } from 'react-intl';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Select from '@material-ui/core/Select';
import FormControl from '@material-ui/core/FormControl';
import MenuItem from '@material-ui/core/MenuItem';
import IconButton from '@material-ui/core/IconButton';
import RightArrowIcon from '@material-ui/icons/ChevronRight';
import LeftArrowIcon from '@material-ui/icons/ChevronLeft';
import messages from './messages';

class CalendarToolBar extends React.PureComponent {
  handleChange = (event) => {
    this.props.onView(event.target.value);
  };

  render() {
    const { view, views, onNavigate, label } = this.props;
    return (
      <Toolbar>
        <Typography variant="headline" style={{ textTransform: 'capitalize', width: '100%' }}>{label}</Typography>
        <div style={{ width: '100%', textAlign: 'right' }}>
          <IconButton onClick={() => onNavigate('PREV')}><LeftArrowIcon /></IconButton>
          <IconButton><RightArrowIcon onClick={() => onNavigate('NEXT')} /></IconButton>
          <FormControl style={{ marginLeft: 16 }}>
            <Select
              value={view}
              onChange={this.handleChange}
            >
              {views.map((value) => <MenuItem value={value}><FormattedMessage {...messages[value]} /></MenuItem>)}
            </Select>
          </FormControl>
        </div>
      </Toolbar>
    );
  }
}

CalendarToolBar.propTypes = {
  onView: PropTypes.func,
  onNavigate: PropTypes.func,
  label: PropTypes.string,
  view: PropTypes.string,
  views: PropTypes.array,

};

export default CalendarToolBar;

excellent, thanks!

It is a big no no to do inheritance in react! see docs here

You dont really need to use the Toolbar from rbc just use the onNavigate function passed from rbc

here is my code:

export default class CalendarToolbar extends React.Component {
  render() {
    return (
      <div className="rbc-btn-group">
          <button
            className="toolbar-navigation-button"
            type="button"
            onClick={() => **this.props.onNavigate**('PREV')}
          >
            <Icon
              className="navigate-icon"
              icon={this.props.isRTL ? 'chevron-right' : 'chevron-left'}
            />
          </button>
          <span
            className="today-label"
            onClick={() => **this.props.onNavigate**('TODAY')}
          >
            {i18n('calendar-today')}
          </span>
          <button
            className="toolbar-navigation-button"
            type="button"
            onClick={() => **this.props.onNavigate**('NEXT')}
          >
            <Icon
              className="navigate-icon"
              icon={this.props.isRTL ? 'chevron-left' : 'chevron-right'}
            />
          </button>
        </div>
      </div>
    );
  }
}

I then just pass this class into the components prop in BigCalendar

@Liel208 's answer should deserve more upvotes.

When reading this thread I've been wondering what exactly is the cause of this issue, because from my understanding, the onView props should only be used when you need to change the view from your custom toolbar.

Some people here suggested that to handle onView props implicitly, but the OP does not need to, and do nothing to change view from his/her custom toolbar. So why is this warning thrown?

I got a real "ahha" moment after reading @Liel208 's answer, I missed out the fact that OP is extending from the react-big-calendar's Toolbar. Also, OP is importing the Toolbar wrong, as it is a default import from react-big-calendar, which is actually the Calendar component itself.

Can someone tell me how to modify the state of the calendar from within the custom tool bar component? I want to include a handler but cant seem to add it to the components.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KatiaPosPago picture KatiaPosPago  路  3Comments

dogC76 picture dogC76  路  4Comments

connercms picture connercms  路  3Comments

manutenfruits picture manutenfruits  路  3Comments

ZacharyLangley picture ZacharyLangley  路  3Comments