React-dates: maximumNights property

Created on 16 Nov 2016  路  7Comments  路  Source: airbnb/react-dates

Is it possible to add maximumNights property to set amount of maximum days to select?

feature request

Most helpful comment

Like the length of the range? So for instance, you can choose a max range of 7 days?

I would say that we don't necessarily need another prop for this because I think you can probably do this with the current implementation like so:

class DateRangePickerWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      focusedInput: START_DATE,
      startDate: null,
      endDate: null,
    };

    this.onDatesChange = this.onDatesChange.bind(this);
    this.onFocusChange = this.onFocusChange.bind(this);
  }

  onDatesChange({ startDate, endDate }) {
    this.setState({ startDate, endDate });
  }

  onFocusChange(focusedInput) {
    this.setState({ focusedInput });
  }

  render() {
    // I assume you will have this either as a constant or a prop in your wrapper
    const { maximumNights } = this.props; 
    const { focusedInput, startDate, endDate } = this.state;

    let isOutsideRange;
    if (startDate) {
      isOutsideRange = day => (
        // this prevents the user from selecting an end date before the start date or after maximumNights days after the start date
        focusedInput === END_DATE && (day.isBefore(startDate) || day.isAfter(startDate.clone().add(maximumNights, 'days')))
      );
    }

    return (
      <div>
        <DateRangePicker
          isOutsideRange={isOutsideRange}
          onDatesChange={this.onDatesChange}
          onFocusChange={this.onFocusChange}
          focusedInput={focusedInput}
          startDate={startDate}
          endDate={endDate}
        />
      </div>
    );
  }
}

Does this work for you? You can play around with the customization of isOutsideRange to get it to limit your user however you specifically want.

All 7 comments

Like the length of the range? So for instance, you can choose a max range of 7 days?

I would say that we don't necessarily need another prop for this because I think you can probably do this with the current implementation like so:

class DateRangePickerWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      focusedInput: START_DATE,
      startDate: null,
      endDate: null,
    };

    this.onDatesChange = this.onDatesChange.bind(this);
    this.onFocusChange = this.onFocusChange.bind(this);
  }

  onDatesChange({ startDate, endDate }) {
    this.setState({ startDate, endDate });
  }

  onFocusChange(focusedInput) {
    this.setState({ focusedInput });
  }

  render() {
    // I assume you will have this either as a constant or a prop in your wrapper
    const { maximumNights } = this.props; 
    const { focusedInput, startDate, endDate } = this.state;

    let isOutsideRange;
    if (startDate) {
      isOutsideRange = day => (
        // this prevents the user from selecting an end date before the start date or after maximumNights days after the start date
        focusedInput === END_DATE && (day.isBefore(startDate) || day.isAfter(startDate.clone().add(maximumNights, 'days')))
      );
    }

    return (
      <div>
        <DateRangePicker
          isOutsideRange={isOutsideRange}
          onDatesChange={this.onDatesChange}
          onFocusChange={this.onFocusChange}
          focusedInput={focusedInput}
          startDate={startDate}
          endDate={endDate}
        />
      </div>
    );
  }
}

Does this work for you? You can play around with the customization of isOutsideRange to get it to limit your user however you specifically want.

Thank you for the awesome library :) This one worked for me,

  import { DateRangePicker, isInclusivelyBeforeDay, isInclusivelyAfterDay } from 'react-dates';
  import moment from 'moment';
  import { START_DATE, END_DATE } from 'react-dates/constants';

  class DateRange extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            focusedInput: null,
            startDate: null,
            endDate: null,
        };

        this.onDatesChange = this.onDatesChange.bind(this);
        this.onFocusChange = this.onFocusChange.bind(this);
    }

    onDatesChange({ startDate, endDate }) {
        this.setState({ startDate, endDate });
    }

    onFocusChange(focusedInput) {
        this.setState({ focusedInput });
        if(focusedInput === START_DATE) {
          this.setState({ endDate: null });
        }
    }


    render() {
        const { focusedInput, startDate, endDate } = this.state;
        let minimumNights  = 1;
        let maximumNights = 5;
        let maximumEndDate = moment().add(maximumNights, 'days');
        let condition;

        if(startDate){
            maximumEndDate = startDate.clone().add(maximumNights, 'days')
        }

        if(focusedInput === END_DATE) {
            condition = (day) => !isInclusivelyAfterDay(day, moment()) || isInclusivelyAfterDay(day, maximumEndDate);
        }

        if(focusedInput === START_DATE) {
            condition = (day) => !isInclusivelyAfterDay(day, moment());
        }

        return ( 
            <div>
                <DateRangePicker
                  {...this.props}
                  onDatesChange={this.onDatesChange}
                  onFocusChange={this.onFocusChange}
                  focusedInput={focusedInput}
                  startDate={startDate}
                  endDate={endDate}
                  numberOfMonths={1}
                  startDatePlaceholderText={"Check In"}
                  endDatePlaceholderText={"Check Out"}
                  minimumNights={minimumNights}
                  isOutsideRange={condition}
                />
            </div>
        );
    }
}

How did this work for you, isOutsideRange should be passed a function not a variable

My bad, it is a function. The new ES Standard. My apologies.

@madsithlord thanks, works perfectly! better than @majapw's solution for sure

I want to limit the maximum days to be selected from the startDate to be 15 days and at the same time I want to block the past dates and dates that are beyond 200 days.

I tried it with the isOutsideRange prop but it seems to accept only one of the applied conditions
Any possible solutions to this?

@NikhilFairfest Unsurprisingly you can implement all the logic within the isOutsideRange function. The following example is taken from a custom wrapping component, which allows to combine the properties maximumDays, disablePastDates, disableFutureDates and a custom implementation passed to it called isOutsideRange:

isOutsideRange = (day: Moment): boolean => {
    const { value: { startDate, endDate }, focusedInput } = this.state;
    const { disablePastDates, disableFutureDates, maximumDays, isOutsideRange } = this.props;
    const today = moment();

    // prevent to select an end date which is before the start date
    if (startDate && focusedInput === "endDate" && day.isBefore(startDate, "day")) {
      return true;
    }
    if (disablePastDates && today.isAfter(day, "day")) {
      return true;
    }
    if (disableFutureDates && today.isBefore(day, "day")) {
      return true;
    }
    if (maximumDays && startDate) {
      const maxDate = startDate.clone().add(maximumDays, "day");
      if (focusedInput === "endDate" && maxDate.isBefore(day)) {
        return true;
      }
    }
    if (isOutsideRange) {
      return isOutsideRange(day);
    }

    return false;
  };
Was this page helpful?
0 / 5 - 0 ratings