Make VueJS and jQuery play nice

This question is related/similar to Using intl-tel-input and vuejs2 together , which is still unanswered.

And VueJS Use prop as data-attribute value which has a solution, but explains a bit the "environment".

So, long story short, I am dynamically setting up a new bootstrap tab (Title and URL), and then trying to (re)bind some functionality using jQuery.

Adding the following line https://github.com/thecodeassassin/bootstrap-remote-data/blob/master/js/bootstrap-remote-tabs.js#L258 in my Vue method will apply the functionality, but only if I trigger the change twice.

The same issue with the first (unanswered) question.

Could someone explain a bit how the things work between vueJS and jQuery ? And how to solve things, hopefully without needing to rewrite jQuery packages.

If I console.log my variables just seem one step behind.

LE:

I have prepared a Pen for the related mentioned issue: https://codepen.io/AngelinCalu/pen/LWvwNq

Answers:

Answer

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.

Answer

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>

I have to admit that this is still not the ideal solution, because there might still be a race condition going. The only way to make sure that no race condition exists is to wait for the plugin to trigger a custom callback once the phone number is parsed and validated, which you can listen on the input element in VueJS. Right now I see that the plugin only has a custom callback for country change.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.