Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 841
Angelin Calu Avatar asked Apr 05 '17 20:04

Angelin Calu


People also ask

Can I use Vue and jQuery together?

If you're careful about how you do it, you can use jQuery and Vue together safely. In this article I'm going to demonstrate how to add the jQuery UI Datepicker plugin to a Vue project. And just to show off a bit, I'm even going to send data between this jQuery plugin and Vue! See it working in this JS Bin.

Can Vue replace jQuery?

Although you can replace jQuery with Vue, you'll need to change your mindset about how to solve Web development problems.

Is VueJS MVVM or MVC?

js is an open-source model-view-view model (MVVM) JavaScript framework.


2 Answers

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.

like image 172
Roy J Avatar answered Oct 14 '22 06:10

Roy J


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.

like image 29
Terry Avatar answered Oct 14 '22 05:10

Terry