Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Can't properly choose time range within boundaries #597

Closed
SilverIrbis opened this issue Apr 21, 2021 · 4 comments
Closed

[Bug] Can't properly choose time range within boundaries #597

SilverIrbis opened this issue Apr 21, 2021 · 4 comments

Comments

@SilverIrbis
Copy link

Vue2-datepicker version: 3.9.0
Vue version:2.3.3
Browser:Electron 2.0.9

Steps to reproduce
I created a datetime picker with a range, so I need to select datetime in a specific spectre of time, from 13.11.2020 12:57:33 to 13.11.2020 13:18:31 and disable any other time, for example.
When I set disabled-date (or disabled-time as well) I face some problems with disabled "ending-time" of the picker for some reason.
I set default-value too, as a period [13.11.2020 12:57:33, 13.11.2020 13:18:30] (it doesn't help if I'm trying to add secong to the start and subtract second from the end just to be sure that default period inside enabled scope)

My code for now looks like:

<date-picker
      v-model="period"
      type="datetime"
      range
      format="DD.MM.YYYY HH:mm:ss"
      input-class="datetime"
      :default-value="periodDefault"
      :disabled-date="disableDays"
      value-type="date">
</date-picker>
disableDays(date) {
      let date0 = new Date(this.dateStart) //13.11.2020 12:57:33
      date0.setHours(0, 0, 0, 0) // need to set hours, minuts, etc in 0, otherwise picker can't display this one enabled date
      let date1 = new Date(this.dateEnd) //13.11.2020 13:18:30
      date1.setHours(0, 0, 0, 0)

      return date < date0 ||
        date > date1
    },

Expected behavior
I can choose any time aside disabled time period

Actual behavior
In the case with disabled-date only or with disabled-time too I'm facing that there is blocked hours before 13 in end-section of timepicker and after 12 in start-section (yet I should be able to choose time range inside 12 or 13 hour too).

This one is only with disabled-date (and I want to get period 12:57 - 12:59)
321
This one with disabled-time too (and I want to get period 12:57 - 12:59 or 13:10 - 13:11)
123

Help me, please. I've seen a lot of issues but still can't figure out how to make it works right

@mengxiong10
Copy link
Owner

It is very difficult for the current components to disable the minute and second.
You can change the disabled boundaries.

<date-picker
  v-model="value4"
  type="datetime"
  range
  :default-value="start"
  :disabled-date="disabledDate"
  :disabled-time="disabledTime"
  @change="handleChange"
></date-picker>
const start = new Date(2020, 10, 13, 12, 57, 33);
const end = new Date(2020, 10, 13, 14, 18, 30);

export default {
  data() {
    return {
      start,
      end,
      value4: [],
    };
  },
  methods: {
    handleChange(dates) {
      if (Array.isArray(dates)) {
        this.value4 = dates.map(v => {
          if (v < this.start) {
            return new Date(this.start);
          }
          if (v > this.end) {
            return new Date(this.end);
          }
          return v;
        });
      }
    },
    disabledDate(date) {
      return (
        date.getTime() < new Date(this.start).setHours(0, 0, 0, 0) ||
        date.getTime() > new Date(this.end).setHours(23, 59, 59, 999)
      );
    },
    disabledTime(date) {
      return (
        date.getTime() < new Date(this.start).setMinutes(0, 0, 0) ||
        date.getTime() > new Date(this.end).setMinutes(59, 59, 999)
      );
    },
  },
};

You can also disable it more finely. This should be controlled by the component and may be improved in the future.

disabledTime(date, index) {
  const [startValue, endValue] = this.value4
  if (index === 0) {
    if (startValue.getHours() === this.start.getHours()) {
      return ...
    }
    if (startValue.getHours() === this.end.getHours()) {
      return ...
    }
  }
},

@Tofandel
Copy link

Tofandel commented Jun 22, 2021

I have the same issue, I think this problem could easily be solved by retrying the function if the returned value is false with the last millisecond of the range instead of providing them at the first (eg Check if first hour is disabled send 01:00:00 => returns true => check with 01:59:59 => returns false this hour shouldn't be disabled because a time within the hour can be selected)

The same could be done for dates, it would make the functions a lot more intuitive and you could just pass the same function for both of them as then this would work as expected by comparing dates

Don't know If my explanation is very clear

Right now I'm doing this, but the issue is that I don't know if the function is checking the hour or the minutes (which only the lib knows as of now) and so this will make the the first minute be enabled, basically there should be a parameter passed to the function

  // Currently, which is quite buggy
  isDisabledTime(d) {
    if (d.getMinutes() === 0 && d < this.minTime) {
      d.setMinutes(59, 59, 999);
    }
    return d < this.minTime || d > this.maxTime;
  },
  // Generic Change that would work where rangeCheck is 1000 when checking seconds, 60000 when checking minutes and 3600000 when checking hours
  isDisabledTime(d, rangeCheck) {
     if (d < this.minTime) {
         d.setMilliseconds(d.getMilliseconds() + rangeCheck)
    }
    return d < this.minTime || d > this.maxTime;
  },
  
  // Intuitively first thing I wrote which resulted in the second screenshot
  isDisabledTime(d) {
    return d < this.minTime || d > this.maxTime;
  },

image

image

So the main issue is we are missing information in those functions about what range is being checked

@Tofandel
Copy link

Tofandel commented Jun 22, 2021

This is how I managed to implement the range solution super hackishly myself but it's less than ideal as it depends on the order of the call and it's impossible to guess the range for the first call (making the first minute always enabled)

      isDisabledTime(d) {
        let range = this.lastChecked ? d.getTime() - this.lastChecked : 0;

        this.lastChecked = d.getTime();

        if (range < 0) {
          range = 360000;
        }

        if (range && d < this.minTime) {
          d = new Date(d);
          d.setMilliseconds(d.getMilliseconds() + range);
        }
        return d < this.minTime || d > this.maxTime;
      },

So I would be for removing the time check all together and just have a "disabled" function

Passing three params

 // Generic change that would work where rangeCheck is 1000 when checking seconds, 60000 when checking minutes, 3600000 when checking hours and 86400000 when checking days
  isDisabled(d, rangeCheck, current) {
     if (d < this.minTime) {
         d.setMilliseconds(d.getMilliseconds() + rangeCheck)
    }
    return d < this.minTime || d > this.maxTime;
  },

@mengxiong10
Copy link
Owner

mengxiong10 commented Aug 30, 2021

v3.10.1 improved it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants