3

I have created a custom component for select that shows all the time for a single day in 15 min interval. I can also pass a optional min-start-time value. In my html, I have used two of these components. I have defined the component as

Vue.component('time-select', {
   template: `
    <select :value="value" 
      ref= 'input'
      v-on:input="onChange($event.target.value)">
        <option value=""> {{firstOption}} </option>
        <option v-for="t in getHours()" :value="t">
          {{ t }}
        </option>
    </select>
 `,
 props: {
    value: String,
    startTime: String,
    firstOption: {
      type: String,
      default: "Select"
    },
    step: {
      type: Number,
      default: 15
    }
 },
 methods: {
   getHours: function() {    
      var startHr = 0;
      var startMin = 0;
      if (this.startTime) {
         var timeParts = this.startTime.split(/[\s:]+/);
         startHr = parseInt(timeParts[0]);
         startMin = parseInt(timeParts[1]);    
         var ampm = timeParts[2];
         if(ampm == "PM" && startHr < 12)
           startHr = startHr + 12;
         else if(ampm == "AM" && startHr === 12)
           startHr = startHr - 12;
     }      

     var hours = [];
     var start = new Date(1,1,1,startHr,startMin);  
     var end = new Date(1,1,2,0,0);
     if(this.startTime)
     {
        start.setMinutes(start.getMinutes() + this.step);
     }
     for (var d = start; d < end; d.setMinutes(d.getMinutes() + this.step)) 
     {          
        hours.push(this.format(d));
     }

      return hours;
   },
   format: function(date)
   {
      var hours = date.getHours();
      var minutes = date.getMinutes();
      var ampm = hours < 12? "AM" : (hours=hours%12,"PM");
      hours =  hours == 0? 12 : hours < 10? ("0" + hours) : hours;
      minutes = minutes < 10 ? ("0" + minutes) : minutes;
      var ret = hours + ":" + minutes + " " + ampm;
      return ret;
   },
   onChange: function(val) {
      this.$emit('input', val);
   },
}
});

JsFiddle link is https://jsfiddle.net/xsnswxu1/1/

Now, if you select any value (e.g. 01:30 am) from the first drop down and any value (e.g. 03:30 am) from the second dropdown, and then again change the value of first dropdown to 12:30 am, the value of second dropdown automatically changes (for this example, it is 02:30 am). VM data retains the same though. When I change the first dropdown, the second dropdown value shouldn't be changed. Any idea what I'm doing wrong. VM is not updated which is good but the second dropdown display value is changing if I change the first dropdown.

2
  • 1
    If the first start time changes, how can the end time be valid, given that the second time's values are based off the start time? If anything, changing the start time should clear the end time. Commented Apr 29, 2017 at 23:29
  • As long as the end time is valid, it should remain the same. VM data stays same. I don't know why vue updates the html value. Am I missing something or is it an issue of Vue. Commented Apr 30, 2017 at 4:46

1 Answer 1

2

Whenever you are iterating with v-for you should add a key property.

When Vue is updating a list of elements rendered with v-for, it by default uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will simply patch each element in-place and make sure it reflects what should be rendered at that particular index.

If you change your template to the following it should work the way you expect.

<select :value="value" 
  ref= 'input'
  v-on:input="onChange($event.target.value)">
  <option value=""> {{firstOption}} </option>
  <option v-for="t in getHours()" :value="t" :key="t">
    {{ t }}
  </option>
</select>

Updated fiddle.

The code still has a bug, however. If you pick a start date and end date, and then pick a start date that makes the end date invalid (because the start now starts after the end date), then your Vue (what you're calling vm) will contain an invalid end date, even though the end date select list will look like the selected end date was cleared. This is why I recommended above that the end date be cleared when the start date changes. If you do not, then you will need to check the validity of the end date whenever the start date changes.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you so much. It works now. And yes, I would clear the end date when it becomes invalid.
I added a method to clear the end time when it is invalid. Fiddle Link
I have found that getHours() method is executed each time I change the dropdown value. Is there any better way to do it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.