最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin4浏览0评论

I am looking to create a form with a datepicker in my React ponent 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?

I am looking to create a form with a datepicker in my React ponent 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?

Share Improve this question asked Dec 18, 2018 at 23:29 MattMatt 5,6843 gold badges29 silver badges40 bronze badges 5
  • Do not believe there is an onSelect - did you mean onChange ? – SakoBu Commented Dec 19, 2018 at 1:03
  • 1 I've been trying this for weeks but everything's in vain, even I'd like to know its answer. – Germa Vinsmoke Commented Dec 19, 2018 at 4:54
  • @SakoBu I addressed that in the question. Neither seem to provide the desired behavior – Matt Commented Jan 7, 2019 at 23:56
  • Oh I have the same problem... it's really hard... for the timepicker I can do it with onBlur... but not working with datepicker – Lucas Moyano Angelini Commented Feb 22, 2019 at 21:06
  • Check this repository in this I've tried to make all the Javascript ponents which are provided by Materialize CSS - github./GermaVinsmoke/Reactize – Germa Vinsmoke Commented May 13, 2019 at 17:36
Add a ment  | 

6 Answers 6

Reset to default 3

Hi hopefully this will help somebody -

What happens with the <DatePicker /> ponent 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 ponents like the <input /> works as per normal. Check it out:

This is what the ponent 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.

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

The use of the ponent:

    <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.ponentWillReceiveProps(props);
  }

  ponentWillReceiveProps(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>;
  }


  ponentDidMount() {
    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>);

  }
}

Thanks Lucas, your answer also helped me.

Here is my solution -without redux or props, just the class ponent 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 {
  ponentDidMount() {
    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;

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;

ponentDidMount(){
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")

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();
    }
    ponentDidMount() {
        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

I made a less elegant solution, but it's also quite a few lines of code. And it seems to be working (after hours of debugging!).

I made a css-class called trouble and applied it to all the fields dealing with DatePicker and TimePicker. In the intialization I created eventlisteners to check for changes. When a change had been detected it calles the _valueTracker, and causes it to send an update event that redux notices.

One very strange thing is that if I pass in the exactly the same value as on e.target.value, it does nothing. It needs to be a string of something random such as "UPDATE!" in this case. I use this code along with the rest of the materialize initialization.

const troubles = document.querySelectorAll(".trouble");
troubles.forEach((item) => {
  item.addEventListener("change", (e) => {
    e.target._valueTracker.setValue("UPDATE!");
  });
});
发布评论

评论列表(0)

  1. 暂无评论