About Anthony Gore
If you enjoyed this article, show your support by buying me a coffee. You might also enjoy taking one of my online courses!
It can then be instantiated by selecting it and calling the method:
$('#datepicker').datepicker();
To make our datepicker component, the template will be this one input
element:
Vue.component('date-picker', function() {
template: '<input/>'
});
new Vue({
el: '#app'
});
<div id="app">
Date: <date-picker></date-picker>
</div>
Note: this component should be nothing more than a wrapper for the plugin. Don't push your luck and give it any data properties or use directives or slots.
Rather than giving our input
an ID and selecting it, we can use this.$el
, as every component can access its own root node like that. The root node will of course be the input
.
We can then wrap the node reference in a jQuery selector to access the datepicker
method i.e. $(this.$el).datepicker()
.
Note that we use the mounted
lifecycle hook as this.$el
is undefined until the component is mounted.
Vue.component('date-picker', function() {
template: '<input/>',
mounted: function() {
$(this.$el).datepicker();
}
});
To teardown the datepicker we can follow a similar approach and use a lifecycle hook. Note that we must use beforeDestroy
to ensure our input
is still in the DOM and thus can be selected (it's undefined in the destroy
hook).
Vue.component('date-picker', {
template: '<input/>',
mounted: function() {
$(this.$el).datepicker();
},
beforeDestroy: function() {
$(this.$el).datepicker('hide').datepicker('destroy');
}
});
To make our component reusable, it would be nice to allow for custom configuration, like specifying the date format with the configuration property dateFormat
. We can do this with props
:
Vue.component('date-picker', {
template: '<input/>',
props: [ 'dateFormat' ],
mounted: function() {
$(this.$el).datepicker({
dateFormat: this.dateFormat
});
},
beforeDestroy: function() { ... }
});
<div id="app">
<date-picker date-format="yy-mm-dd"></date-picker>
</div>
Let's say that, rather than passing your dateFormat
prop as a string, you made it a data
property of your root instance i.e.:
var vm = new Vue({
data: {
...
dateFormat: 'yy-mm-dd'
}
});
<div id="app">
<date-picker date-format="dateFormat"></date-picker>
</div>
This would mean dateFormat
would be a reactive data property. You could update its value at some point in the life of your app:
// change the date format to something new
vm.dateFormat = 'yy-dd-mm';
Since the dateFormat
prop is a dependency of the datepicker component's mounted
hook, updating it would trigger the component to re-render. This would not be cool. jQuery has already setup your datepicker on the input
and is now managing it with it's own custom classes and event listeners. An update of the component would result in the input
being replaced and thus jQuery's setup would be instantly reset.
We need to make it so that reactive data can't trigger an update in this component...
The v-once
directive is used to cache a component in the case that it has a lot of static content. This in effect makes the component opt-out from updates.
This is actually perfect to use on our plugin component, as it will effectively make Vue ignore it. This gives us some confidence that jQuery is going to have unhampered control over this element during the lifecycle of the app.
<div id="app">
<date-picker date-format="yy-mm-dd" v-once></date-picker>
</div>
It'd be pretty useless to have a datepicker if we couldn't retrieve the picked date and use it somewhere else in the app. Let's make it so that after a value is picked it's printed to the page.
We'll start by giving our root instance a date
property:
new Vue({
el: '#app',
data: {
date: null
}
});
<div id="app">
<date-picker date-format="yy-mm-dd" v-once></date-picker>
<p>{{ date }}</p>
</div>
The datepicker widget has an onSelect
callback that is called when a date is picked. We can then use our component to emit this date via a custom event:
mounted: function() {
var self = this;
$(this.$el).datepicker({
dateFormat: this.dateFormat,
onSelect: function(date) {
self.$emit('update-date', date);
}
});
}
Our root instance can listen to the custom event and receive the new date:
<div id="app">
<date-picker @update-date="updateDate" date-format="yy-mm-dd" v-once></date-picker>
<p>{{ date }}</p>
</div>
new Vue({
el: '#app',
data: {
date: null
},
methods: {
updateDate: function(date) {
this.date = date;
}
}
});
Thanks to this Stack Overflow answer for inspiration.
Click to load comments...