2 votes

react-modal : Comment faire en sorte que la modale s'étende automatiquement lorsque l'on clique sur react-datepicker (code joint) ?

Comment faire en sorte que la modale s'étende automatiquement lorsque l'on clique sur react-datepicker ? La modale s'adapte initialement, mais lorsque vous cliquez sur le champ de la date et que le react-datepicker affiche le calendrier, la boîte de dialogue react-modal ne s'étend pas automatiquement ?

Avant : enter image description here

Après avoir cliqué sur la date : enter image description here

Code :

import React, { useState } from 'react';
import Modal from 'react-modal';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";

const customStyles = {
  content: {
    top: '50%',
    left: '50%',
    right: 'auto',
    bottom: 'auto',
    marginRight: '-50%',
    transform: 'translate(-50%, -50%)',
  },
};

export default function TestPage2() {
  const [modalIsOpen, setIsOpen] = React.useState(false);
  const [startDate, setStartDate] = useState(new Date());

  function openModal() {
    setIsOpen(true);
  }

  function closeModal() {
    setIsOpen(false);
  }

  return (
    <div>
      <button onClick={openModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        onRequestClose={closeModal}
        contentLabel="Example Modal"
        style={customStyles}
      >
        <h3>Prior to Date Picker</h3>
        <label htmlFor="Checkin Date">Checkin Date</label>
        <DatePicker
          selected={startDate}
          // wrapperClassName="datePicker"
          // className="form-control"
          dateFormat="d MMMM yyyy"
          name="checkinDate"
          onChange={(date, event) => {
            if (date) {
              setStartDate(date)
            }
          }}
          />
          <h3>After Date Picker</h3>
      </Modal>
    </div>
  );
}

2voto

Omid Poorali Points 91

Ajoutez la propriété suivante à votre objet de contenu à l'intérieur de customStyles :

 overflow: 'hidden'

et changez les valeurs des propriétés de la classe react-datepicker-popper :

.react-datepicker-popper {
  position: static!important;
  transform: none!important;
}

codesandbox : https://codesandbox.io/s/awesome-feather-mj81tz

1voto

Athii Points 140

J'ai rencontré exactement le même problème il y a quelques semaines. Je cherchais une solution facile mais je n'en ai pas trouvé. Ce que j'ai fait est de diviser le Datepicker en 2 composants (+ redux).

  1. Est-ce que votre contribution <Datepicker />

enter image description here

  1. Est-ce que votre sélecteur de date flottant <DatepickerFloatingItem/>

enter image description here

Afficheur de date

Le sélecteur de date est simplement le champ d'entrée et c'est le composant que vous pouvez utiliser dans toute votre application web react. Le plus grand changement ici est que vous devez exécuter une action avec le dispatcher pour afficher l'élément flottant. De plus, vous devez déterminer les coordonnées X et Y de votre Datepicker pour placer l'élément flottant au bon endroit.

Voici à quoi pourrait ressembler le composant Datepicker (j'ai supprimé le code logique pour ne pas embrouiller tout le monde) :

class DatetimePicker extends React.Component<IDatetimePickerProps, IDatetimePickerState> {

    public componentDidMount() {
        this.updateDate(this.props.date);
        window.addEventListener("resize", this.updateDimensions);
    }

    public componentWillUnmount() {
        // display the floating datepicker even when resizing the window
        window.removeEventListener("resize", this.updateDimensions);
    }

    ///
    /// LOGIC CODE (deleted)
    ///

    private showCalendar = (): void => {
        const { date, key } = this.state;
        const { dispatch } = this.props;
        const { showFloating } = this.props.datePickerState

        if (!showFloating) {
            this.createOutsideClickEvent();
            if (date) {
                this.updateDate(date);
            }
        } else {
            this.removeOutsideClickEvent();
        }

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect) {
            dispatch(updateDatepickerData({ updateDate: this.updateDate, showFloating: true, date, positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, key }))
        }
    }

    private updateDimensions = (): void => {
        const { dispatch } = this.props;
        const { date, showFloating } = this.props.datePickerState;
        const { key } = this.state;

        var boundingRect = document.getElementById(key)?.getBoundingClientRect();
        if (boundingRect && this.props.datePickerState.key === key) {
            dispatch(updateDatepickerData({ positionX: boundingRect.left, positionY: boundingRect.top + boundingRect.height, date, showFloating }))
        }
    }

    public render(): React.ReactNode {
        const { input, wrapperRef, key } = this.state;
        const { style, disabled, className, onClick, styleWrapper, icon } = this.props;

        return <span className="datetimepicker" ref={wrapperRef} onClick={onClick} style={styleWrapper}>
            <Input
                className={`datetimepicker__input ${className}`}
                value={input}
                onChange={this.updateInput}
                getFocus={this.disableErrorView}
                getBlur={this.textInputLostFocus}
                rightButtonClicked={this.showCalendar}
                style={style}
                id={key}
                icon={icon}
                disabled={disabled}
            />
        </span>
    }
}

DatepickerFloatingItem

Vous ne devez positionner le DatepickerFloatingItem qu'une seule fois dans votre application. Il est préférable de le positionner dans App.js (le composant racine).

Il est également important d'avoir position: relative pour l'élément parent et définir position: fixed pour le DatepickerFloatingItem. Maintenant, vous pouvez facilement positionner votre élément flottant en utilisant top: y left: avec les coordonnées du Datepicker

Et voici à quoi pourrait ressembler le DatepickerFloatingItem (j'ai également supprimé le code inutile pour le rendre plus compréhensible)

interface IDatepickerFloatingItemStateProps {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
}

class DatepickerFloatingItem extends React.Component<IDatepickerFloatingItemProps, IDatepickerFloatingItemState> {

    private clickedFloatingDatepicker = (event: React.MouseEvent<HTMLSpanElement>): void => event.preventDefault()
    private updateDate = (date?: Date, closeFloating?: boolean): void => {
        const { dispatch } = this.props;

        dispatch(updateDatepickerDate(date ? date : new Date()))
        if (closeFloating) dispatch(updateDatepickerShowFloating(!closeFloating))
    }

    public render(): React.ReactNode {
        const { showFloating, date, positionX, positionY } = this.props;
        const { datepickerView } = this.state;

        return <span className={`datetimepicker__floating ${showFloating ? "show" : ""}`} onClick={this.clickedFloatingDatepicker} style={{ top: `${positionY}px`, left: `${positionX}px` }}>
            <DateCalendar datepickerView={datepickerView} date={date} updateDate={this.updateDate} />
        </span>
    }
}

function mapStateToProps(applicationState: ApplicationState): IDatepickerFloatingItemStateProps {
    return {
        date: applicationState.datepicker.date,
        showFloating: applicationState.datepicker.showFloating,
        positionX: applicationState.datepicker.positionX,
        positionY: applicationState.datepicker.positionY
    }
}

export default connect(mapStateToProps)(DatepickerFloatingItem)

Redux

J'ai dû déplacer certaines choses vers le magasin Redux pour m'assurer que les FloatingDatePicker ainsi que le Afficheur de date avoir la possibilité de communiquer d'une manière ou d'une autre

J'ai gardé le magasin redux assez simple :

import { Action, Reducer } from 'redux';

export interface DatepickerState {
    date: Date
    showFloating: boolean
    positionX?: number
    positionY?: number
    updateDate?: (date?: Date) => void
}

export const UPDATE_DATEPICKER_SHOWFLOATING = "UPDATE_DATEPICKER_SHOWFLOATING";
export const UPDATE_DATEPICKER_DATA = "UPDATE_DATEPICKER_DATA";
export const UPDATE_DATEPICKER_DATE = "UPDATE_DATEPICKER_DATE";

export interface UpdateDatepickerShowFloating {
    type: "UPDATE_DATEPICKER_SHOWFLOATING"
    showFloating: boolean
}

export interface UpdateDatepickerDate {
    type: "UPDATE_DATEPICKER_DATE"
    date: Date
}

export interface UpdateDatepickerData {
    type: "UPDATE_DATEPICKER_DATA"
    state: DatepickerState
}

type KnownAction = UpdateDatepickerShowFloating | UpdateDatepickerData | UpdateDatepickerDate

const unloadedState: DatepickerState = { updateDate: () => { }, date: new Date(), showFloating: false, showTime: false, positionX: 0, positionY: 0 }

export const reducer: Reducer<DatepickerState> = (state: DatepickerState | undefined, incomingAction: Action): DatepickerState => {

    if (state === undefined) {
        return unloadedState;
    }

    const action = incomingAction as KnownAction;

    switch (action.type) {
        case UPDATE_DATEPICKER_SHOWFLOATING:
            return { ...state, showFloating: action.showFloating }
        case UPDATE_DATEPICKER_DATE:
            setTimeout(() => { if (state.updateDate) state.updateDate(action.date) }, 1)
            return { ...state, date: action.date }
        case UPDATE_DATEPICKER_DATA:
            return { ...state, ...action.state }
        default:
            break;
    }

    return state;
}

Et comme vous pouvez le voir sur l'image, il fonctionne en fait à l'intérieur d'une modale : enter image description here

Je sais que cette approche prend beaucoup de temps, mais j'espère quand même qu'elle vous a aidé d'une manière ou d'une autre et j'espère aussi que vos yeux ne brûlent pas à force de voir des composants basés sur des classes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X