A jQuery datepicker is wrappped in a Vue component. The component emits an update message used to update the app model.
The app has two datepicker input fields:
startDate
adjustmentDate
When startDate
is modified, adjustmentDate
is to be updated to the next first or fifteenth of the month. However, the adjustmentDate
datepicker component is not being notified of the update.
Expected behaviour:
startDate
datepicker onSelect
triggers the Vue component emit
which is captured by Vue method updateStartDate
method updateStartDate
sets model property adjustmentDate
It was hoped this would trigger the adjustmentDate
component update since the adjustmentDate
model attribute is bound to the datepicker componentDate
property which has a watch.
But changing the model doesn't have the affect of notifying the component.
Any suggestions how to do this properly and show the newly calculated adjustmentDate
when the startDate
is changed?
Demo code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://unpkg.com/vue"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>
<body>
<div id="app">
<div><label>Start date</label></div>
<div>
<date-picker
v-model="startDate"
v-bind:component-date="startDate"
date-format="yy-mm-dd"
@update-date="updateStartDate"
v-once
></date-picker>
</div>
<div><label>Adjustment date</label></div>
<div>
<date-picker
v-model="adjustmentDate"
v-bind:component-date="adjustmentDate"
date-format="yy-mm-dd"
@update-date="updateAdjustmentDate"
v-once
></date-picker>
</div>
</div>
<script>
Vue.component('date-picker', {
props: ['dateFormat', 'componentDate'],
template: '<input/>',
mounted: function() {
var self = this;
var _convertDateStringToDate = function(dateString) {
var dateParts = dateString.split("-");
var year = dateParts[0];
var month = dateParts[1];
var dayOfMonth = dateParts[2];
return new Date(year, month, dayOfMonth);
};
$(this.$el).datepicker({
dateFormat: this.dateFormat,
onSelect: function(date) {
self.$emit('update-date', _convertDateStringToDate(date));
},
onClose: function(date) {
self.$emit('update-date', _convertDateStringToDate(date));
}
});
$(this.$el).datepicker('setDate', this.componentDate);
},
watch: {
componentDate: function(newValue, oldValue) {
$(this.$el).datepicker('setDate', this.componentDate);
}
},
beforeDestroy: function() {
$(this.$el).datepicker('hide').datepicker('destroy');
}
});
var _calculateAdjustmentDate = function(date) {
var year = date.getFullYear();
var month = date.getMonth();
var dayOfMonth = date.getDate();
if (dayOfMonth > 15) {
month = month + 1;
dayOfMonth = 1;
} else if (dayOfMonth > 1 && dayOfMonth < 15) {
dayOfMonth = 15;
}
return new Date(year, month, dayOfMonth);
};
var data = function() {
var now = new Date();
return {
startDate: now,
adjustmentDate: _calculateAdjustmentDate(now),
};
};
new Vue({
el: '#app',
data: data,
methods: {
updateStartDate: function(date) {
this.startDate = date;
this.adjustmentDate = _calculateAdjustmentDate(date);
},
updateAdjustmentDate: function(date) {
this.adjustmentDate = date;
},
}
});
</script>
</body>
</html>
You need to remove the v-once directive from your adjustment date component as it prevents re-rendering when the data changes.
Additionally, you can simply put _calculateAdjustmentDate
into a computed property, see Computed Properties.
See your updated example here: https://codepen.io/anon/pen/VQYarZ
There are some other issues with your code, I suggest you look into the Vue guide, especially at Method Event Handlers and Computed Properties as well as into Reactivity in Depth.
Also, _calculateAdjustmentDate
does not really do what you describe, so you might look into this as well. You might consider Moment.js