New fiddle answer: https://jsfiddle.net/ghLmnm2c/483/
I thought about this more, and went with an older strategy I mentioned when I first tried to help you, and removed the computed properties as this might have something to do with the way the component renders. So instead I replicated the functionality using the plugin's event emitters, and added a watcher on the interval plugin to get you the same functionality.
Here's what the html looks like:
Start Date: <date-picker v-model="startDate" :config="config" @dp-change="updateEndDateInterval"></date-picker>
End Date: <date-picker v-model="endDate" :config="config" @dp-update="updateInterval"></date-picker>
Interval: <input class="form-control" type="text" v-model="interval" @keyup="updateEndDate">
I figured that the only inputs that will change the endDate is the startdate and the interval.
So here are the methods:
methods: {
updateEndDateInterval: function() {
this.updateEndDate(); //this automatically hits updateInterval because of @dp-change="updateInterval" on the enddate component
},
updateEndDate: function() {
this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days');
},
updateInterval: function(v) {
if (this.periods > 0) {
var dateVal = ""
if (v.target) {
dateVal = v.target.value;
} else {
dateVal = v;
}
this.interval = (moment(dateVal).diff(this.startDate, 'days')+1) / this.periods;
}
}
}
The updateInterval accepts a v parameter, the v will take in the passed moment object from updateEndDateInterval, or the event object when changing the value of the interval input textbox. If you pass in the this.endDate from the interval textbox, you run into a circular reference, where interval will update enddate, enddate will update interval and so on and so forth.
Also, you need to set endDate to have a reactive property
data: {
interval: 7,
startDate: moment(),
endDate: '' // leave this empty
}
when you load the component, update the endDate property to whatever the startdate value (defined in updateEndDate):
mounted: function(){
this.updateEndDate();
}
I checked all functionality compared to your old fiddle, and I checked for the reactivity. Personally, I like this strategy more as you are using the prefered methods mentioned in the plugin, I didn't really see any examples of computing properties being used. This also makes things more modular as you can tweak when necessary without accidently modifying other components.
I was going to give the interval textbox a vue watcher and have it set to the updateEndDate like this:
//don't do this
watch: {
interval: function() {
this.updateEndDate()
}
}
But this code doesn't work, because of the circular reference problem. This will crash your browser. So that's why I went with the @keyup event. When you change the interval from the startdate or enddate, the interval changes, and because there's a watch on it, it creates a circular reference as it continuously updates itself. That's why triggering the updateEndDate via keyup event is triggered based on key inputs, so selecting dates won't interfere with the update of the interval.
Answer to the underlying problem (fixed).
Used this answer as a reference:
Passing event and argument to v-on in Vue.js
I put a flag to prevent you from updating the interval when you change the startdate, and to prevent the interval from changing itself when setting the enddate.
<date-picker v-model="endDate" :config="config" @dp-change="updateInterval($event, intervalUpdate)"></date-picker>
then add reactive property to data:
data: {
intervalUpdate: true
}
update the methods:
updateEndDateInterval: function() {
this.intervalUpdate = false; //do not update interval
...
},
updateEndDate: function() {
this.intervalUpdate = false;
...
},
updateInterval: function(v, shouldUpdate) {
console.log(shouldUpdate);
if (shouldUpdate) {
this.intervalUpdate = shouldUpdate;
}
if (this.intervalUpdate) {
....
}
this.intervalUpdate = true; //reset the flag
}
(FIXED)
Now, the underlying problem you have. Updating enddate and interval date using startdate. You couldn't see it when you were using computer properties. Which is the reason why you couldn't edit your interval correctly.
If you change only the enddate, the formula for calculating the interval works correctly, because you're ONLY changing the interval. However, changing the startdate changes the enddate AND interval.
When selecting startDate both needs to be updated, but it can't because both formulas depends on each other, you get stale data if you switch the order of execution:
So, if you try to update the enddate first, you can't because this.interval is stale, as this will give you the incorrect value of this.endDate, and using the incorrect value of enddate in the next line for calculating the interval will give you incorrect result.
//stale this.interval value as it isn't updated before
this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days').format('DD MMM YYYY');
//incorrect this.endDate to give incorrect this.interval
this.interval = (moment(this.endDate).diff(this.startDate, 'days')+1) / this.periods;
if you try to reverse the order, you can't because this.endDate is stale, it's not updated so your interval value becomes incorrect. And when you execute the next line, this.endDate becomes incorrect because of the incorrect value of this.interval
//stale this.endDate value as it isn't updated before
this.interval = (moment(this.endDate).diff(this.startDate, 'days')+1) / this.periods;
//incorrect this.interval used to give incorrect this.endDate
this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days').format('DD MMM YYYY');