Make VueJS and jQuery play nice Make VueJS and jQuery play nice vue.js vue.js

Make VueJS and jQuery play nice


The way to make Vue play nicely with other DOM-manipulating toolkits is to completely segregate them: if you are going to use jQuery to manipulate a DOM widget, you do not also use Vue on it (and vice-versa).

A wrapper component acts as a bridge, where Vue can interact with the component and the component can manipulate its internal DOM elements using jQuery (or whatever).

jQuery selectors outside of lifecycle hooks are a bad code smell. Your validatePhoneNumber uses a selector and a DOM-manipulating call, but you are using Vue to handle keydown events. You need to handle everything on this widget with jQuery. Don't use Vue to set its class or phone_number or handle its events. Those are all DOM manipulations. As I mentioned, if you wrap it in a component, you can pass props to the component and from those props you can use jQuery to set class and phone_number.


I think the reason behind it is that when the keydown event is fired, the internal workings of the plugin kicks in and does not immediately expose the phone values. This results in a race condition where you prematurely retrieves the phone number value before it is being updated internally by the plugin itself.

This issue can simply be resolved by listening to other events, such as keyup or input:

const app = new Vue({  el: '#app',  data: {    phone_number: "",    validPhone: false  },  methods: {    validatePhoneNumber: function() {      var phone_element = $('#phone');      var validPhoneNo = phone_element.intlTelInput("isValidNumber");      var phoneNo = phone_element.intlTelInput("getNumber");      console.log(phoneNo + ' -> ' + validPhoneNo); // I am interested in both values    }  },  mounted: function() {    $('#phone').intlTelInput({      utilsScript: "js/utils.js",      initialCountry: "auto",      geoIpLookup: function(callback) {        $.get('https://ipinfo.io', function() {}, "jsonp").always(function(resp) {          var countryCode = (resp && resp.country) ? resp.country : "";          callback(countryCode);        });      },      preferredCountries: []    });  }});
<link href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/11.0.10/css/intlTelInput.css" rel="stylesheet" /><link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" /><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.4/vue.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/11.0.10/js/utils.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/11.0.10/js/intlTelInput.min.js"></script><div id="app">  <div class="row">    <div class="col-sm-offset-2 col-sm-6">      <input class="form-control" @input="validatePhoneNumber" :class="{validInput: validPhone }" name="phone" value="" ref="phone_element" :phone_number="phone_number" type="text" id="phone" />    </div>  </div></div>