Search code examples
javascriptreactjsdate-rangeflatpickr

react-flatpickr range selection with two inputs populating both the dates in first input


I am using react-flatpickr range plugin providing code below:

Index.js

import React from "react";
import ReactDOM from "react-dom";
import DatePicker from "./datePicker.js";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <DatePicker
        options={{
          dateFormat: "d-M-Y",
          defaultDate: "",
          disableMobile: "true",
          maxDate: "today"
        }}
        fromDateID="DashboardEndDatePicker"
        selectValue={[]}
        placeholder="From Date"
      />
      &nbsp;&nbsp;&nbsp;&nbsp;
      <input id="DashboardEndDatePicker" placeholder="To Date" />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

datePicker.js

import React, { Component } from "react";
import Flatpickr from "react-flatpickr";
import rangePlugin from "flatpickr/dist/plugins/rangePlugin";
import "flatpickr/dist/flatpickr.min.css";
import "flatpickr/dist/themes/light.css";

export default class DatePicker extends Component {
  constructor(props) {
    super(props);
    this.setDate = this.setDate.bind(this);
    this.clearDate = this.clearDate.bind(this);

    this.state = {
      selectValue: props.selectValue ? props.selectValue : "",
      options: props.options
        ? Object.assign({}, props.options, {
            plugins: [new rangePlugin({ input: "#" + props.fromDateID })]
          })
        : { plugins: [new rangePlugin({ input: "#" + props.fromDateID })] },
      disabled: props.disabled ? props.disabled : false,
      placeholder: props.placeholder ? props.placeholder : ""
    };
  }

  componentWillReceiveProps(newProps) {
    this.setState({
      selectValue: newProps.selectValue ? newProps.selectValue : "",
      options: newProps.options
        ? Object.assign({}, newProps.options, {
            plugins: [new rangePlugin({ input: "#" + newProps.fromDateID })]
          })
        : { plugins: [new rangePlugin({ input: "#" + newProps.fromDateID })] },
      disabled: newProps.disabled ? newProps.disabled : false,
      placeholder: newProps.placeholder ? newProps.placeholder : ""
    });
  }

  clearDate() {
    this.refs.refDatePicker.flatpickr.clear();
  }

  setDate(newValue) {
    this.setState({
      selectValue: newValue ? newValue : ""
    });
    if (this.props.onChange) {
      this.props.onChange(newValue);
    }
  }

  render() {
    return (
      <Flatpickr
        className="form-control clickable"
        disabled={this.state.disabled}
        ref="refDatePicker"
        placeholder={this.state.placeholder}
        options={this.state.options}
        value={this.state.selectValue}
        onChange={this.setDate}
      />
    );
  }
}

When ever I am selecting "to date" it is setting the same in "from date" field as well. Providing image below:

enter image description here

I have created a code sand box for the same:

Sandbox Link

Not sure what I am missing here.


Solution

  • Figured out the issue. setDate was creating the problem. What was happening is:

    1. you change the date, flatpickr updates the date1 to date2 because in the core library that's the only way it knows how to display ranges

    2. the rangePlugin comes above that and updates the value again, adding logic to display ranges in multiple inputs

    3. you come after the range plugin and basically repeat step 1, thus overwritting step 2

    Removing setDate worked for me.

    import React, { Component } from "react";
    import Flatpickr from "react-flatpickr";
    import rangePlugin from "flatpickr/dist/plugins/rangePlugin";
    import "flatpickr/dist/flatpickr.min.css";
    import "flatpickr/dist/themes/light.css";
    
    export default class DatePicker extends Component {
      constructor(props) {
        super(props);
        this.setDate = this.setDate.bind(this);
        this.clearDate = this.clearDate.bind(this);
    
        this.state = {
          options: props.options
            ? Object.assign({}, props.options, {
                plugins: [new rangePlugin({ input: "#" + props.fromDateID })]
              })
            : { plugins: [new rangePlugin({ input: "#" + props.fromDateID })] },
          disabled: props.disabled ? props.disabled : false,
          placeholder: props.placeholder ? props.placeholder : ""
        };
      }
    
      componentWillReceiveProps(newProps) {
        this.setState({
          options: newProps.options
            ? Object.assign({}, newProps.options, {
                plugins: [new rangePlugin({ input: "#" + newProps.fromDateID })]
              })
            : { plugins: [new rangePlugin({ input: "#" + newProps.fromDateID })] },
          disabled: newProps.disabled ? newProps.disabled : false,
          placeholder: newProps.placeholder ? newProps.placeholder : ""
        });
      }
    
      clearDate() {
        this.refs.refDatePicker.flatpickr.clear();
      }
    
      setDate(newValue) {
        if (this.props.onChange) {
          this.props.onChange(newValue);
        }
      }
    
      render() {
        return (
          <Flatpickr
            className="form-control clickable"
            disabled={this.state.disabled}
            ref="refDatePicker"
            placeholder={this.state.placeholder}
            options={this.state.options}
            onChange={this.setDate}
          />
        );
      }
    }
    

    Code Sand Box Link