web-dev-qa-db-fra.com

Comment capturer correctement la valeur de datepicker Materialize-CSS dans React?

Je cherche à créer un formulaire avec un datepicker dans mon React avec materialize-css . Je n'ai pas beaucoup de champs ce le formulaire est en train de capturer et la structure est assez simple. Le formulaire retourné ressemble à ceci:

<form onSubmit={this.handleSubmit.bind(this)}>
     <div className="container">
          <div className="card grey lighten-3">
               <div className="card-content black-text">
                    <span className="card-title">
                            <input placeholder="Event Name"
                                    name="name" value={this.state.name}
                                    onChange={this.handleStateChange.bind(this)}/>
                    </span>
                    <input name="description" placeholder="Description"
                                      value={this.state.description}
                                      onChange={this.handleStateChange.bind(this)}/>
                    <input name="image" placeholder="Image URL"
                                      value={this.state.image}
                                      onChange={this.handleStateChange.bind(this)}/>
                    <input placeholder="Start Date"
                                className="datepicker" name="startDate" value={this.state.startDate}
                                onSelect={this.handleStateChange.bind(this)}/>
                </div>
                <div class="card-action">
                    <div className="row">
                        <span>
                           <div className="col s3">
                               <input className="btn light-blue accent-1" type="submit" value="Submit"/>
                           </div>
                           <div className="col s3">
                               <a className="btn grey" onClick={this.handleExpand.bind(this)}>Cancel</a>
                           </div>
                       </span>
                   </div>
               </div>
           </div>
       </div>
   </form>

Le changement d'état est géré avec

handleStateChange(item) {
    this.setState({[item.target.name]: item.target.value});
}

et j'ai appelé le AutoInit pour initialiser mon datepicker

M.AutoInit();

J'ai essayé d'utiliser onChange au lieu de onSelect pour gérer le changement d'état du sélecteur de date, mais il ne semble pas capturer cet événement. Avec onSelect utilisé, la date est parfois capturée si je choisis une date puis rouvre le sélecteur de dates.

J'ai également essayé d'utiliser certains des méthodes d'initialisation alternatives pour le sélecteur de date en vain.

Comment capturer correctement le changement d'entrée avec ma configuration donnée?

10
Matt

Salut, j'espère que cela aidera quelqu'un -

Ce qui se passe avec le composant <DatePicker /> est que la méthode onChange par défaut renvoie la date (2019-08-01) et non l'objet gestionnaire d'événements de l'élément. Afin de contrer cela, nous devons créer un objet à l'intérieur de la méthode onChange qui imite les target.id et target.value du gestionnaire d'événements.

D'autres composants comme <input /> fonctionnent comme d'habitude. Vérifiez-le:

Voici à quoi devrait ressembler le composant:

            <DatePicker
                label="myDate"
                value={state.myDate}
                id="myDate"
                onChange={(newDate) => {
                    handleChange({
                        target: {
                            id: "myDate",
                            value: newDate
                        }
                    })
                }} />

Voici le code complet:

import React, { useState, useEffect } from "react";
import "materialize-css/dist/css/materialize.min.css";
import "materialize-css/dist/js/materialize.min.js";
import { DatePicker } from "react-materialize";

const PickDate = (props) => {

    const [state, setState] = useState({myName: "Mags", myDate: "2019-08-01"});

    const handleChange = (e) => {
        const key = e.target.id;
        const val = e.target.value;

        const newState = {...state};
        newState[key] = val;
        setState(newState);
    }

    return (
        <React.Fragment>
            <input type="text" value={state.myName} id="myName" onChange={handleChange} />
            <DatePicker
                label="myDate"
                value={state.myDate}
                id="myDate"
                onChange={(newDate) => {
                    handleChange({
                        target: {
                            id: "myDate",
                            value: newDate
                        }
                    })
                }} />
        </React.Fragment>
    );
}

export default PickDate;

PS. cela utilise React Hooks - mais cela fonctionnera aussi sur les classes normales.

2
Magnus Esterhuizen

Merci Lucas, ta réponse m'a aussi aidé.

Voici ma solution -sans redux ou accessoires, juste le composant de classe avec son propre état

import React, { Component } from "react";
import "./calendar.css";
import Materialize from "materialize-css";
import moment from "moment";

class Calendar extends Component {
  componentDidMount() {
    var context = this;

    var elems = document.querySelectorAll(".dateset");
    Materialize.Datepicker.init(elems, {
      defaultDate: new Date(),
      format: this.state.format,
      container: "body",
      onSelect: function(date) {
        context.setState({ value: context.state.value });
        console.log(date); // Selected date is logged
      },
      autoClose: true
    });
  }

  state = {
    value: new Date(),
    format: "ddd d, mmm",
    formatMoment: "ddd D, MMM"
  };

  render() {
    return (
      <div className="input-field col s6">
        <i className="material-icons prefix">date_range</i>
        <input
          id="date"
          type="text"
          className="datepicker dateset"
          defaultValue={moment(this.state.value).format(
            this.state.formatMoment
          )}
        />
      </div>
    );
  }
}

export default Calendar;
1
mrs_suis

Aucune des réponses déjà ajoutées ne m'a aidé, alors j'ai décidé de le faire à ma façon. Je n'ai pas installé Materialise et jQuery dans mes modules, je les ai juste ajoutés dans index.html

Lorsque vous cliquez sur le champ de saisie, la fenêtre modale datepicker s'ouvre et il y a deux boutons CANCEL et OK. Je trouve ce bouton OK par jQuery et ajoute une fonction de clic, qui prend la valeur du champ de saisie et met à jour l'état;

componentDidMount(){
window.$(".datepicker-done").click(() => {
      var datepickerValue = window.$("#date-input").val();  // date-input it's 'id' on datepicker input

      this.setState({ approxLastDay: datepickerValue });
    });
}

REMARQUE: datepickerValue sera au format chaîne (par exemple, "6 août 2019")

0
airush

J'ai le même problème, voici ma solution.

import React, { Component } from 'react'
import M from 'materialize-css';

class CreateReport extends Component {
    constructor(props) {
        super(props);
        this.state = {
            startDate: '',
            endDate: ''
        };
        // refs for startDate, endDate
        this.startDate = React.createRef();
        this.endDate = React.createRef();
    }
    componentDidMount() {
        var context = this;
        document.addEventListener('DOMContentLoaded', function () {
            var start = document.querySelectorAll('.datepicker');
            M.Datepicker.init(start, {
                format: "mm/dd/yyyy",
                autoClose: true,
                onClose: context.handleDate
            });
        });
    }
    handleDate = () => {
        this.setState({
            startDate: this.startDate.current.value,
            endDate: this.endDate.current.value,
        })
        // console.log(this.state.startDate)
        // console.log(this.state.endDate)
    }
    handleChange = (e) => {
        this.setState({
            [e.target.id]: e.target.value
        })
    }
    handleSumbit = (e) => {
        e.preventDefault();
        console.log(this.state)
    }
    render() {
        return (
            <div>
                <div className="container">
                    <form onSubmit={this.handleSumbit} className="white col s12 m6">

                        <div className="row">
                            <div className="input-field col s3 offset-s2">
                                <label htmlFor="date">Start Date</label>
                                <input
                                    type="text"
                                    className="datepicker"
                                    id="startDate"
                                    onChange={this.handleChange}
                                    value={this.state.startDate}
                                    ref={this.startDate}
                                />
                            </div>
                            <div className="input-field col s3 offset-s2">
                                <label htmlFor="date">End Date</label>
                                <input
                                    type="text"
                                    className="datepicker"
                                    id="endDate"
                                    onChange={this.handleChange}
                                    value={this.state.endDate}
                                    ref={this.endDate} />
                            </div>
                        </div>
                        <div className="col s8 offset-s2 center-align">
                            <button className="btn pink lighten-1 z-depth-0 ">Sign Up</button>
                        </div>

                    </form>
                </div>
            </div >
        )
    }
}
export default CreateReport
0
Khanh Luu

Après avoir étudié tout le samedi sur le cycle de vie de React. J'ai obtenu cette solution pour cela:

L'utilisation du composant:

    <DatePicker label="Fecha" value={this.state.formSchedule.start} 
onChange={(date) => {
    this.state.formSchedule.start = date;
    this.setState({ formSchedule: this.state.formSchedule });
}}/>

La classe DatePicker.tsx:

    import * as React from 'react';
import Materialize from 'materialize-css';
import moment from 'moment'
import 'moment/locale/es'
import { any } from 'prop-types';


interface IState {
  value: any;
}

interface IProps {
  label: any;
  format: any;
  onChange: any;
  formatMoment: any;
}

export default class DatePicker extends React.Component<IProps, IState> {

  static defaultProps = {
    label: "Fecha",
    value: new Date(),
    format: 'ddd d, mmm',
    formatMoment: 'ddd D, MMM'
  }

  constructor(props: any) {
    super(props);
    this.componentWillReceiveProps(props);
  }

  componentWillReceiveProps(props) {
    this.state = {
      value: props.value
    };
  }

  render() {
    return <div className="input-field col s6">
      <i className="material-icons prefix">date_range</i>
      <input id="date" type="text" className="datepicker queso"
        value={moment(this.state.value).locale('es').format(this.props.formatMoment)}
      />
      <label className="active" htmlFor="date">{this.props.label}</label>
    </div>;
  }


  componentDidMount() {
    var context = this;

    var elems = document.querySelectorAll('.queso');
    Materialize.Datepicker.init(elems, {
      defaultDate: new Date(),
      format: this.props.format,
      container: 'body',
      onSelect: function (date) {
        context.setState({ value: context.state.value });
        context.props.onChange(date);
      },
      autoClose: true
    } as Partial<any>);

  }
}
0
Lucas Moyano Angelini