How do I correctly capture Materialize-CSS datepicker value in React?

你说的曾经没有我的故事 提交于 2020-02-27 21:13:42

问题


I am looking to create a form with a datepicker in my React component with materialize-css. I don't have many fields this form is capturing and the structure is fairly simple. The form returned looks like this:

<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>

The state change is handled with

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

and I have called the AutoInit to initialize my datepicker

M.AutoInit();

I've tried using onChange instead of onSelect to manage the datepicker state change, but it doesn't seem to capture that event. With onSelect used, the date sometimes gets capture if I pick a date then re-open the datepicker.

I have also tried using some of the alternate initialization methods for the datepicker to no avail.

How do I correctly capture the input change with my given setup?


回答1:


Hi hopefully this will help somebody -

What happens with the <DatePicker /> component is that the default onChange method returns the date (2019-08-01) and not the the element's event handler object. In order to counter this we need to create an object inside the onChange method that mimics the eventhandler's target.id and target.value

Other components like the <input /> works as per normal. Check it out:

This is what the component should look like:

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

Here is the full code:

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. this uses React Hooks - but it will work on normal classes too.




回答2:


Thanks Lucas, your answer also helped me.

Here is my solution -without redux or props, just the class component with its own state

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;



回答3:


After studing all the saturday about the lifecycle of React. I got this solution for this:

The use of the component:

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

The Class 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>);

  }
}



回答4:


None of the already added answers helped me, so I decided to do it in my way. I did not install Materialize and jQuery into my modules, just added them in index.html

When you click on input field, then datepicker modal window opens and there two buttons CANCEL and OK. I find that OK button by jQuery and add click function, which takes value from input field and updates the state;

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

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

NOTE: datepickerValue will be in string format (e.g. "Aug 6, 2019")




回答5:


I having the same problem, here is my 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


来源:https://stackoverflow.com/questions/53842589/how-do-i-correctly-capture-materialize-css-datepicker-value-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!