When using Vue.js for my projects I tend to avoid jQuery because it messes with the DOM, which can cause unexpected side-effects, however it does have one of the most reliable date pickers around, and if you already have jQuery in your project it’s a good choice. So let’s look at how we might build a ‘bridge’ component that allows us to create a reusable jQuery date picker component in Vue.js.

Firstly, when creating these types of components it’s best to use a custom directive, which keeps our code nice and clean. So let’s start by creating a directive that simply attaches the jQuery date picker to an input:

<template>
  <div>
    <input type="text" v-date-picker />
  </div>
</template>

<script type="text/javascript">
export default{
  directives: {
    datePicker: {
      bind(el, binding, vnode) {
        $(el).datepicker();
      }
    }
  }
}
</script>

Here we have added a directive called datePicker that we are attaching to our input using v-date-picker. That’s quite straightforward if you’re familiar with custom directives, so if you try this now you should get a functioning jQuery date picker menu: https://jsfiddle.net/vuetiful/h5dqrLh9/

Now we need to get the date out of the component and back to our parent. The date picker won’t work with v-on:input because the input event isn’t fired when we select a date, instead we need to use the date picker’s onSelect option to emit an event, so let’s do that:

<template>
  <div>
    <input type="text" v-date-picker/>
  </div>
</template>

<script type="text/javascript">
export default{
  directives: {
    datePicker: {
      bind(el, binding, vnode) {
        $(el).datepicker(
          vnode.context.$emit('input', val);
        });
      }
    }
  }
}
</script>

Here we have used vnode.context to get the context and emit an event called “input”, this is equivalent to doing this.$emit('input', val). The name here is important, because v-model listens for the input event, so here we have fired our own custom input event meaning that we can use v-model on the component itself:

<date-picker v-model="myDate"></date-picker>

That’s all working great, but we also want to add the ability for a user to type the date as well, so let’s emit the input event on user input by attaching the @input event to our text input:

<input type="text" @input="$emit('input', $event.target.value)" v-date-picker  >

And finally we may want to add a default value, so let’s create a prop called “date” and bind it using v-bind:value, so our final date-picker component looks like this:

<template>
  <div>
    <input type="text" @input="$emit('input', $event.target.value)" v-bind:value="date" v-date-picker />
  </div>
</template>

<script type="text/javascript">
export default{
props: {
    date: {
      default: '',
      type: String,
    }
  },
  directives: {
    datePicker: {
      bind(el, binding, vnode) {
        $(el).datepicker({
          onSelect: function(val) {
            vnode.context.$emit('input', val);
          }
        });
      }
    }
  }
}
</script>

And here’s the final JSFiddle: https://jsfiddle.net/vuetiful/60nauta8/

Advertisements