React-big-calendar: Rendering a custom popover

Created on 12 Jun 2018  路  11Comments  路  Source: jquense/react-big-calendar

Feature --
I have enable isSelectable in my calendar, but want to have the user select a few timeslots and have a popup menu being rendered after they have selected. Essentially, I want to render a react component after onSelectSlot is called. Is there any way to do this?

The only thing i can think of right now is injecting something in the DOM when onSelectSlot is called but I can't take advantage of react then. I don't see a react class i can override in components for this either.

Does anyone have any suggestions?

Most helpful comment

I am closing this for now since the original poster is not active. Thanks @joshuawootonn for your response!

All 11 comments

I am not a contributor, but you can use any css framework that has a modal or popover component for this.

I am using Material-ui for that very purpose right now. Modal & Popover

I am using custom events react class like

class CustomEvent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isModalOpen: 0
    };
  }

  handleOpen = () => {
    this.setState({ isModalOpen: 1 });
  };

  handleClose = () => {
    this.setState({ isModalOpen: 0 });
  };
  render() {    
    const { classes } = this.props;

    const startm = moment(Date.parse(start)).format("h:mm a");
    return (
      <div>
        <div onClick={this.handleOpen}>
          {/* whatever you want to display for your event*/}
        </div>
        <Modal
          aria-labelledby="simple-modal-title"
          aria-describedby="simple-modal-description"
          open={this.state.isModalOpen}
          onClose={this.handleClose}
        >
          <div className={classes.paper}>
            {/*whatever you want to display in the popup*/}
          </div>
        </Modal>
      </div>
    );
  }
}

Then when I am instantiating my BigCalendar component I specify my event component like:

<BigCalendar
  events={events}
  defaultDate={new Date()}        
  components={{
    event: CustomEvent,
  }}
 />

The problem I have with this approach is that it doesn't seem to work when you click on the date header. Wouldn't overwriting the EventWrapper work a lot better :)
Downside being that you can't have access to the event object.

You are right. I just went back and checked, and I actually changed the code after posting my answer because of that problem.

I believe setting .rbc-event's z-index fixes that problem.

.rbc-event {
  z-index: 999 !important;
}

Hopefully this doesn't break your styling conventions. It did break mine, but I couldn't find a better solution. Let me know if find something better.

Additionally I refactored my Calendar like so

export class Calendar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isAddModalOpen: false,
      isEditModalOpen: false,
    };
  }

  toggleAddModal = event => {
    if (!this.state.isEditModalOpen) {
      this.setState({
        currentEvent: event,
        isAddModalOpen: !this.state.isAddModalOpen,
      });
    }
  };
  toggleEditModal = event => {    
    if (!this.state.isAddModalOpen) {
      this.setState({
        currentEvent: event,
        isEditModalOpen: !this.state.isEditModalOpen,
      });
    }
  };
  render() {
    const { classes, toolbarVisible, defaultView } = this.props;

    return (
      <div className={classes.calendarWrapper}>
        <BigCalendar
          selectable
          onSelectSlot={this.toggleAddModal}
          onSelectEvent={this.toggleEditModal}
          // Any other props you are using
        />
        <Modal open={this.state.isAddModalOpen} toggle={this.toggleAddModal}>
            // whatever is displayed when you click the calendar
        </Modal>
        <Modal open={this.state.isEditModalOpen} toggle={this.toggleEditModal}>
            // whatever is displayed when you click an event
        </Modal>
      </div>
    );
  }
}

Sorry for the long snippet. I believe this is a better solution because my modals will contain forms that are connected components(Redux). Having one form at the Calendar level reduces unneeded connections.

I am closing this for now since the original poster is not active. Thanks @joshuawootonn for your response!

Referencing #803

@joshuawootonn Thanks for your approach; however your approach only works on modal where you can set open for your field in Material-ui or show from react-bootstrap; I'm more interested in Popover where you do not have afield where you can use state to toggle. @joshuawootonn @arecvlohe Could you please help with a popover approach; this issue seems the problem most people are facing for react-big-calendar; I appreciate your help.

Any help on this for popover or any similar solution from any CSS framework?

No update/help/direction here?!

@Amir-61 I don't understand what you are looking for. You can use the same approach for a Popover component like the modal one. Simply write a custom event component and use your framework you like the most. But you have to set your open/show state manually anyways.

I stumbled opon this issue trying to figure out correct way of introducing popovers to calendar (quite common use case). I ended up doing it like that:

export function EventPopoverWrapper({ children, popover }: Props): any {
  const [anchorEl, setAnchorEl] = React.useState<HTMLDivElement | null>(null);

  const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const open = Boolean(anchorEl);
  const id = open ? 'simple-popover' : undefined;

  return (
    <>
      <div aria-describedby={id} onClick={handleClick}>
        {children}
      </div>
      <Popover
        id={id}
        open={open}
        anchorEl={anchorEl}
        onClose={handleClose}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'center',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'center',
        }}
      >
        {popover}
      </Popover>
    </>
  );
}

Then in actual calendar:

          eventWrapper: props => (
            <EventPopoverWrapper
              {...props}
              popover={
                <OffAssignmentsCalendarPopover
                  assignment={props.event}
                  userEntities={userEntities}
                />
              }
            />
          ),

I stumbled opon this issue trying to figure out correct way of introducing popovers to calendar (quite common use case). I ended up doing it like that:

export function EventPopoverWrapper({ children, popover }: Props): any {
  const [anchorEl, setAnchorEl] = React.useState<HTMLDivElement | null>(null);

  const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const open = Boolean(anchorEl);
  const id = open ? 'simple-popover' : undefined;

  return (
    <>
      <div aria-describedby={id} onClick={handleClick}>
        {children}
      </div>
      <Popover
        id={id}
        open={open}
        anchorEl={anchorEl}
        onClose={handleClose}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'center',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'center',
        }}
      >
        {popover}
      </Popover>
    </>
  );
}

Then in actual calendar:

          eventWrapper: props => (
            <EventPopoverWrapper
              {...props}
              popover={
                <OffAssignmentsCalendarPopover
                  assignment={props.event}
                  userEntities={userEntities}
                />
              }
            />
          ),

Awesome... will try it. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Beyazatli picture Beyazatli  路  3Comments

npalansky picture npalansky  路  3Comments

dogC76 picture dogC76  路  4Comments

kromit picture kromit  路  4Comments

connercms picture connercms  路  3Comments