ParadeTo / vue-date-range

A vue component for choosing dates and date ranges. Uses Moment.js for date operations.
http://paradeto.com/vue-date-range/
36 stars 17 forks source link

Select dateRange doesnt update Calendar view #24

Closed 105th closed 6 years ago

105th commented 6 years ago

Version: "vue-date-range": "^3.0.0"

Here is my code:

      <date-range
        ref="datepicker"
        v-show="showPicker"
        class="calendar dropdown"
        :sync-range.sync="range"
        :lang="currentLocale"
        :emitChangeOnStep0="true"
        v-on-click-away="hideDatepicker"
        :days-disabled-start="maxDate"
        :days-disabled-end="minDate"
      />

I need to update range by button like that 'selectWeek' method:

      this.startDate = Moment().subtract(7, 'days')
      this.endDate = Moment()

But when i use this method, property 'date' of component 'Calendar' didn`t change:

1. State before click 'selectWeek' image 2. State after click 'selectWeek' image

I have looked into src and in Calendar.vue found, that date doesnt properly update when range changed:

   // line 167
    watch: {
      range (val) {
        // this.date = val.startDate
        this.resetDayOfMonth()
      }
   }

and in resetDayOfMonth() method we see this

      resetDayOfMonth () {
        const {
          date,
          dayOfMonth
        } = this
        // If no date is selected then it's not necessary to update dayOfMonth
        if (!date) return
        if (formatter(date, 'YYYY-MM') !== formatter(dayOfMonth, 'YYYY-MM')) {
          let _diff = Number(date.diff(dayOfMonth, 'months'))
          _diff = _diff <= 0 ? _diff - 1 : _diff
          dayOfMonth.add(_diff, 'months')
          this.dayOfMonth = dayOfMonth.clone()
        }
      }

In line if (!date) return we return nothing, because in watch.range method we didn`t change date! If i uncommented this line // this.date = val.startDate it works fine

ParadeTo commented 6 years ago

Can you provide your full code?

105th commented 6 years ago
<template>
  <div class="row">
    <div class="date-selectors">
      <button @click="selectWeek()">Week</button>
      <button>Month</button>
      <button>Year</button>
    </div>

    <div class="date-picker">
      <div class="input-group">
        <masked-input
          mask="11\.11\.1111\-11\.11\.1111"
          v-model="inputDate"
        />
        <img
          @click.prevent.stop="showPicker = !showPicker"
          src="/static/images/elements/calendar.svg"
          alt="Calendar icon"
        >
      </div>

      <date-range
        ref="datepicker"
        v-show="showPicker"
        class="calendar dropdown"
        :sync-range.sync="range"
        :lang="currentLocale"
        :emitChangeOnStep0="true"
        v-on-click-away="hideDatepicker"
        :days-disabled-start="maxDate"
        :days-disabled-end="minDate"
        :disabled-func="disabled"
        :disableDaysBeforeToday="true"
      />
    </div>

  </div>
</template>

<script>
import DateRange from './src/DateRange.vue'
import MaskedInput from 'vue-masked-input'
import { directive as VueClickAway } from 'vue-clickaway'

import { mapMutations } from 'vuex'

import Moment from 'moment'

export default {
  name: 'analytics-filters-datepicker',

  directives: {
    onClickAway: VueClickAway
  },

  components: {
    DateRange,
    MaskedInput
  },

  data () {
    return {
      showPicker: false,
      maxDate: Moment().add(2, 'days'),
      minDate: Moment().subtract(3, 'years')
    }
  },

  computed: {
    currentLocale () {
      return this.$store.state.locale.value
    },

    startDate: {
      get () {
        return this.$store.getters['analytics/createdAfter']
      },

      set (val) {
        this.filtersChange({createdAfter: val})
      }
    },

    endDate: {
      get () {
        return this.$store.getters['analytics/createdBefore']
      },

      set (val) {
        this.filtersChange({createdBefore: val})
      }
    },

    inputDate: {
      get () {
        return this.startDate.format('DD.MM.YYYY') + '-' + this.endDate.format('DD.MM.YYYY')
      },

      set (val) {
        const [startDate, endDate] = val.split('-')

        if (startDate.indexOf('_') === -1 && Moment(startDate, 'DD.MM.YYYY').isValid()) {
          this.startDate = Moment(startDate, 'DD.MM.YYYY')
        }

        if (endDate.indexOf('_') === -1 && Moment(endDate, 'DD.MM.YYYY').isValid()) {
          this.endDate = Moment(endDate, 'DD.MM.YYYY')
        }
      }
    },

    range: {
      get () {
        return {
          startDate: this.startDate,
          endDate: this.endDate
        }
      },

      set (val) {
        if (Moment(val.startDate, 'DD.MM.YYYY').isValid()) {
          this.startDate = Moment(val.startDate, 'DD.MM.YYYY')
        }

        if (Moment(val.endDate, 'DD.MM.YYYY').isValid()) {
          this.endDate = Moment(val.endDate, 'DD.MM.YYYY')
        }
      }
    }
  },

  methods: {
    disabled (...args) {
      console.log(args)
    },

    selectWeek () {
      this.startDate = Moment().subtract(7, 'days')
      this.endDate = Moment()
      this.$refs.datepicker.date = Moment()
    },

    hideDatepicker () {
      if (!this.showPicker) {
        return
      }

      this.showPicker = false
    },

    ...mapMutations('analytics', [
      'filtersChange'
    ])
  }
}
</script>

<style lang="scss" scoped>
  .row {
    position: relative;
  }

  .date-selectors {
    display: flex;

    button {
      font-weight: normal;
      line-height: normal;
      font-size: 16px;
      background: white;
      border: 1px solid #DDDDDD;
      min-width: 80px;
      padding: 10px 0;
      box-sizing: border-box;

      &:first-child { border-radius: 5px 0 0 5px; }
      &:last-child { border-radius: 0 5px 5px 0; }
      &:not(:first-child) { border-left: none; }

      &.active {
        background: #F1F2F2;
      }
    }
  }

  .date-picker {
    margin-left: 12px;

    .input-group {
      display: flex;
      align-items: center;
      position: relative;

      input {
        border-color: #DDDDDD;
        width: 230px;
        padding: 12px 40px 10px 15px;
      }

      img {
        position: absolute;
        right: 12.5px;

        &:hover { cursor: pointer; }
      }
    }

    .calendar {
      position: absolute;
      top: calc(100% + 5px);
      right: 0;
    }
  }

</style>
105th commented 6 years ago

Also you can reproduce bug by using your scr example via and methods 'selectWeek' and try to set range with new dates.

gzoreslav commented 6 years ago

I used in this way

Template:

<date-range class="calendar"
                    :disabled-func="disabledFunc"
                    :sync-range.sync="dateRange"
                    :day-of-month="dayOfMonth"
                    :emitChangeOnStep0=true
                    monthYearFormat="MMMM, YYYY"
                    lang="en"></date-range>

Set range

this.range = {
    startDate: ...;
    endDate: ...;
};

And it works

ParadeTo commented 6 years ago

@105th It is not a good way to set date via refs. @gzoreslav 's way is right.

105th commented 6 years ago

@ParadeTo this line is only to try fix bug. And, if you look into your code, you couldn`t pass property date from DateRange.vue component to Calendar.vue component, so this line is do nothing.

ParadeTo commented 6 years ago

Would you like to "pull a request"?