DEV Community

Lisa Armstrong
Lisa Armstrong

Posted on • Edited on

Using Vue in jQuery and JavaScript Sites

So you've got a legacy project on your desk. You know the type, from back in the day when jQuery was the go-to tool. Now that project needs an update and although jQuery is still a useful tool, you know doing the update would go a lot quicker in Vue.
Ok, let's be honest, you might be looking for an excuse to use Vue -- I won't tell.

The problem is, while the changes are a good candidate for Vue, there's still the rest of the site in jQuery or vanilla JavaScript. You don't want to refactor the whole thing, but dang! Vue would be awfully handy in there. So the question is:
Can I use Vue in a jQuery or vanilla JavaScript site?

Yes you can.

It's All JavaScript Anyway

Although jQuery and Vue are different, they both work with the DOM and use JavaScript.

That means using them in the same file shouldn't be an issue. Think of them as running parallel to each other, like two lanes going the same way on a highway.

In this tutorial, we're going to add Vue functionality to a simple jQuery page and show you how Vue and jQuery (and vanilla JavaScript) can work together in harmony.

We're assuming you know jQuery / JavaScript well, and have worked with Vue. It's nothing fancy, just basic concepts.

The Project

Let's say we're working with an HTML file where you make a selection and it uses jQuery to tell you what's been selected.

This is a standard type of app where the user makes a choice and the code responds. The HTML looks like this:

<html lang="en">
<head>
    <!-- Load JQuery -->
    <script
  src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
  integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8="
  crossorigin="anonymous"></script>
    <script type="text/javascript">
        function doFoodGroup(){
            //Returns what is selected
            var selected = $("input:radio[name ='food_group']:checked").val();
            alert('You selected: '+selected)
        }
    </script>
    <style>
        .demoDiv{
            display: inline-block; 
            width: 49%;
            vertical-align: top;
        }
    </style>
</head>
<body>
    <h1>JQuery and Vue</h1>
    <div class="demoDiv">
        <h2>Select a Food Group:</h2>
        <input type="radio" name="food_group" value="fruit" onclick="doFoodGroup()"> Fruit
        <br>
        <input type="radio" name="food_group" value="veggies" onclick="doFoodGroup()"> Veggie
    </div>
</body>
</html>

Adding functionality through Vue

We're going to update the code, so when a user makes a selection, their choice is displayed on the page. We're going to use Vue to code this, so let's load it.

Adding Vue

To use Vue, you need 3 things:

  1. Load Vue in the page
  2. Build your Vue code
  3. Give it an element on the page to work in

Let's set it up:

1. Add Vue to the page through the header:

<!-- Load Vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

2. Create a file with the Vue code in it, and load it in the HTML header:

The file called 'vue_demo.js'.
It's going to list fruit and veggies, so it looks like:

var vue_choices = new Vue({
    el: '#app', //Attach to element id app
    data: {
        fruits: ["apples", "pears", "peaches", "cherries"], 
        veggies: ["lettuce", "peas", "carrots", "tomatoes"], 
    },
})

Now load the file in the HTML header

<!-- Load script file.  'defer' loads after body is generated -->
<script src="vue_demo.js" defer></script>

3. Create a DIV for Vue to use:

<!-- Div where Vue runs -->
<div id="app" class="demoDiv">
</div>

Not much to see here, so add some code to display the list in the Vue div:

<!-- Div where Vue runs -->
    <div id="app" class="demoDiv">
        <div>
            <h3>Fruit choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="fruit in fruits">
                    <input type="radio" name="food_selected" v-bind:value="fruit">{{ fruit }}
                </li>
            </ul>
        </div>
        <div>
            <h3>Veggie choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="veggie in veggies">
                    <input type="radio" name="food_selected" v-bind:value="veggie">{{ veggie }}
                </li>
            </ul>
        </div>
    </div>

Note: This is a list of radio options because we're selecting them later.

When you look at the page, you should see jQuery 'Select a Food Group' div in one area and Vue's list of fruits and veggies next to it. So, you can have a Vue running in a page using jQuery -- problem solved!

Of course in real life, you'll probably need Vue to interact with the rest of the page. Data needs to go back and forth between Vue and JavaScript.

It's time to change lanes.

Moving Between Vue and Javascript

Because Vue and Javascript are parallel, you can pass variables between them. But, like changing lanes while driving, be careful you don't collide with something!

When working with Vue and jQuery / JavaScript there's a couple of caveats to keep in mind:

1. Stay in Your Lane (When You Can)

Remember you've got two places to write your code -- DOM level JavaScript / jQuery or in Vue. It's easy to be on autopilot and start writing code in Vue, when it would really work better in DOM JavaScript. The next thing you know, you're doing contortions trying to get something on the screen!

GOTCHA! Where you put your code matters.

If your code is in Vue and you're trying to change a div outside of the Vue div (or vice versa), you can run into problems. Sure, there's ways around this, but it can be needlessly complicated.

As a general rule: Put your code where the element you're changing is.

  • If you're changing something within the Vue div, then let Vue handle it.
  • If you're updating a div outside of the Vue div (in the document), then use the regular JavaScript to deal with it.

In other words, stay in your lane (life will be easier).

2. Change Lanes Politely

Of course sooner or later you'll have to pass information from DOM JavaScript to Vue and back again. You need to change lanes.

When changing lanes while driving you make sure the other lane knows you're coming, and you behave predictably. It's the same idea when passing a variable between DOM JavaScript and Vue. Make sure the other side knows what's coming and can deal with it.

As we're about to see, it's not a big trick and usually done through functions.

How To Pass Values to Vue

When you first look up how to pass a value to Vue, you probably found terms like: props, emit, components, parent/child. Do I need to build a component to pass data?

Oh my, this feels complicated!
It's not.

Gotcha! You don't use components to pass parameters into Vue.

Components are great things inside Vue. We're passing data from outside Vue, so it doesn't apply. It's the wrong tool for the job -- it's actually simpler than that.

Remember: Vue is a Javascript Object!

When you loaded Vue, it became an object within Javascript.

The code: var vue_choices = new Vue({
means you've created an JavaScript object called 'vue_choices' in the document. That means it's available to JavaScript in the document. In fact, you can get see the vue_choices object through the console log in the DOM JavaScript.

Ex.: console.log( vue_choices ) would display:

Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$attrs: (...)
$children: []
$createElement: ƒ (a, b, c, d)
$el: div#app.demoDiv
$listeners: (...)
$options: {components: {…}, directives: {…}, filters: {…}, _base: ƒ, el: "#app", …}
$parent: undefined
$refs: {}
$root: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$scopedSlots: {}
$slots: {}
$vnode: undefined
fruits: (...)
veggies: (...)

As you can see, the Vue object is laid out in all its glory. That includes things like variables and functions/ methods.

So, if you wanted to access a Vue variable or method from Javascript in the page, you would use something like:

console.log(vue_choices.fruits)

Which gives you access to the fruits list:

4) ["apples", "pears", "peaches", "cherries", __ob__: Observer]
0: "apples"
1: "pears"
2: "peaches"
3: "cherries"

That means you an reach into Vue and work with any variables or methods.
Now you are drunk with power! Muhahah!

Ok, back to work.

In our example, we want to tell Vue when 'vegetable' or 'fruit' has been chosen. Since we're asking Vue to do the work, it makes sense to write a function/method in Vue. That function can be called from the DOM JavaScript level.

Because the function can take a parameter, it's a way of passing data from the DOM level into Vue.

Let's see this in action.

Create a method in Vue called showChoice(). The method takes a parameter with the choice, and will display a list based on the choice.
Note: The whole show/hide thing uses flag variables, so we'll add them.

The Vue code looks something like:

var vue_choices = new Vue({
    el: '#app', //Attach to element id app
    data: {
        fruits: ["apples", "pears", "peaches", "cherries"],
        veggies: ["lettuce", "peas", "carrots", "tomatoes"],

        //Display
        show_fruits: false,
        show_veggies: false,
    },

    methods: {
        showChoices: function (getChoice) {
            //Set display vars according to choice
            switch (getChoice) {
                case 'fruit':
                    this.show_fruits = true;
                    this.show_veggies = false;
                    break;
                case 'veggies':
                    this.show_fruits = false;
                    this.show_veggies = true;
                    break;
                default:
                    this.show_fruits = false;
                    this.show_veggies = false;
            }
        }
    },   // end methods
})  // end vue

The Vue div uses v-show to handle show/hide and looks like:

<!-- Div where Vue runs -->
    <div id="app" class="demoDiv">
        <div v-show="show_fruits">
            <h3>Fruit choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="fruit in fruits">
                    <input type="radio" name="food_selected" v-bind:value="fruit">{{ fruit }}
                </li>
            </ul>
        </div>

        <div v-show="show_veggies">
            <h3>Veggie choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="veggie in veggies">
                    <input type="radio" name="food_selected" v-bind:value="veggie">{{ veggie }}
                </li>
            </ul>
        </div>
    </div>

Call the Vue Function from JavaScript

Now that the function showChoices() is part of the Vue object vue_choices, you can call it in JavaScript like this: vue_choices.showChoice( ) .

Of course we need to add the choice parameter, which we get in the JavaScript doFoodGroup() function.

The function should look like:

function doFoodGroup() {
//Returns what is selected
            var selected = $("input:radio[name ='food_group']:checked").val();
            alert("You selected: " + selected);

            //Send the selection to Vue
            vue_choices.showChoices(selected);
        }

Putting It Together

At this point the user selects a food type (fruit or veggie) and passes the choice to Vue via a Vue function called in JavaScript.

Your HTML code should look like:

<html lang="en">

<head>
    <!-- Load JQuery -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>

    <!-- Load Vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- Load script file.  'defer' loads after body is generated -->
    <script src="vue_demo.js" defer></script>

    <script type="text/javascript">
        function doFoodGroup() {
            //Returns what is selected

            var selected = $("input:radio[name ='food_group']:checked").val();
            showSelection(selected);

            //Send selection to Vue
            vue_choices.showChoices(selected);
        }

        function showSelection(getSelection) {
            alert("You selected: " + getSelection);
        }
    </script>

    <style>
        .demoDiv {
            display: inline-block;
            width: 49%;
            vertical-align: top;
        }
    </style>
</head>

<body>
    <h1>JQuery and Vue</h1>
    <div class="demoDiv">
        <h2>Select a Food Group:</h2>
        <input type="radio" name="food_group" value="fruit" onclick="doFoodGroup()" /> Fruit
        <br />
        <input type="radio" name="food_group" value="veggies" onclick="doFoodGroup()" /> Veggie
    </div>
    <!-- Div where Vue runs -->
    <div id="app" class="demoDiv">
        <div v-show="show_fruits">
            <h3>Fruit choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="fruit in fruits">
                    <input type="radio" name="food_selected" v-bind:value="fruit" />{{ fruit }}
                </li>
            </ul>
        </div>

        <div v-show="show_veggies">
            <h3>Veggie choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="veggie in veggies">
                    <input type="radio" name="food_selected" v-bind:value="veggie" />{{ veggie }}
                </li>
            </ul>
        </div>
    </div>
</body>

</html>

Your Vue code should look like:

var vue_choices = new Vue({
    el: '#app', //Attach to element id app
    data: {
        fruits: ["apples", "pears", "peaches", "cherries"],
        veggies: ["lettuce", "peas", "carrots", "tomatoes"],

        //Display
        show_fruits: false,
        show_veggies: false,
    },

    methods: {
        showChoices: function (getChoice) {
            //Set display vars according to choice
            switch (getChoice) {
                case 'fruit':
                    this.show_fruits = true;
                    this.show_veggies = false;
                    break;
                case 'veggies':
                    this.show_fruits = false;
                    this.show_veggies = true;
                    break;
                default:
                    this.show_fruits = false;
                    this.show_veggies = false;
            }
        },

    },   // end methods
})  // end vue

Now we're getting some where!

Vue Data Vars vs Methods / Functions

Although you can change a Vue variable directly through JavaScript by using something like:

vue_choices.show_fruits = false

Using a method is probably a better idea. Remember: Change Lanes Politely.

Why? That variable may be manipulated within Vue and JavaScript making changes from the outside may cause problems. So change Vue data vars through a method (and save yourself a headache)!

Passing Data from Vue to Javascript

We just called a Vue method to pass a parameter to Vue from Javascript. If you want to go the other way and pass a parameter from Vue to JavaScript, it's the same idea only backwards. Yup, that means calling a JavaScript function inside Vue.

Note: Yes, you can access the JavaScript variable directly, but a function is less risky if something changes.

In this example, let's say whenever the user selects a specific fruit or veggies, we need to pass that choice back to the function showSelection() in the main document.

As you're pondering this problem, you're probably thinking using an onChange event to fire showSelection() is the solution.
No it's not.

Gotcha! Regular JavaScript events don't work well in Vue elements.

If you try to add a regular 'onchange' event to the element, Vue will ignore it. It uses v-on:click.
If you try to run something like: v-on:click=" showSelection()", that won't work either because showSelection() is not a Vue thing.

Remember, Vue's job is to handle its section of the DOM. If you change an element outside of Vue, it causes problems. Stay in your lane!

Solution: Access JavaScript objects (functions) inside Vue.

Although the Vue DOM doesn't like regular JavaScript (or jQuery) in it, Vue methods are cool using JavaScript objects.
Using jQuery inside your Vue file is possible, but probably not worth the fight. Stick with JavaScript if you can.

So, the approach is:

  1. Create a Vue Method that fires the parent document showSelection()
  2. In the Vue div, use v-onclick="vueMethod()" to run it.

Vue Method

The method is very simple, just run the function defined in the parent document. Make sure it takes a parameter that can be passed to showSelection().

That means it looks something like:

 getSelection: function(selection) {
                showSelection(selection)
            }

Wait! You can just use the JavaScript function defined in the document inside Vue?
Yup, that the whole point.

The function is a JavaScript object, Vue is JavaScript and has access to the objects. That's how it all works.

Your Vue code should look like:

var vue_choices = new Vue({
        el: '#app', //Attach to element id app
        data: {
            fruits: ["apples", "pears", "peaches", "cherries"],
            veggies: ["lettuce", "peas", "carrots", "tomatoes"],

            //Display
            show_fruits: false,
            show_veggies: false,
        },

        methods: {
            showChoices: function(getChoice) {
                //Set display vars according to choice
                switch (getChoice) {
                    case 'fruit':
                        this.show_fruits = true;
                        this.show_veggies = false;
                        break;
                    case 'veggies':
                        this.show_fruits = false;
                        this.show_veggies = true;
                        break;
                    default:
                        this.show_fruits = false;
                        this.show_veggies = false;
                }
            },

            getSelection: function(selection) {
                showSelection(selection)
            }

        }, // end methods
    }) // end vue

Update the Vue Div

We have the method, we want to fire it when a fruit or veggie is selected. So you would change your inputs to something like:

<input type="radio" name="food_selected" v-bind:value="fruit" v-on:click="getSelection(fruit)" /> 

Passing Parameters: Bind Values

You want to pass the value of the input to the method. The value is defined by v-bind:value="fruit", this is what is tied to that input.

Oh, don't forget to change the 'veggie' inputs one too!

Your html file should look like this:

<html lang="en">

<head>
    <!-- Load JQuery -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>

    <!-- Load Vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- Load script file.  'defer' loads after body is generated -->
    <script src="vue_demo.js" defer></script>

    <script type="text/javascript">
        function doFoodGroup() {
            //Returns what is selected

            var selected = $("input:radio[name ='food_group']:checked").val();
            showSelection(selected);

            //Send selection to Vue
            vue_choices.showChoices(selected);
        }

        function showSelection(getSelection) {
            alert("You selected: " + getSelection);
        }
    </script>

    <style>
        .demoDiv {
            display: inline-block;
            width: 49%;
            vertical-align: top;
        }
    </style>
</head>

<body>
    <h1>JQuery and Vue</h1>
    <div class="demoDiv">
        <h2>Select a Food Group:</h2>
        <input type="radio" name="food_group" value="fruit" onclick="doFoodGroup()" /> Fruit
        <br />
        <input type="radio" name="food_group" value="veggies" onclick="doFoodGroup()" /> Veggie
    </div>
    <!-- Div where Vue runs -->
    <div id="app" class="demoDiv">
        <div v-show="show_fruits">
            <h3>Fruit choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="fruit in fruits">
                    <input type="radio" name="food_selected" v-bind:value="fruit" v-on:click="getSelection(fruit)" />{{ fruit }}
                </li>
            </ul>
        </div>

        <div v-show="show_veggies">
            <h3>Veggie choices:</h3>
            <ul id="fruit_list" style="list-style-type: none">
                <li v-for="veggie in veggies">
                    <input type="radio" name="food_selected" v-bind:value="veggie" v-on:click="getSelection(veggie)" />{{ veggie }}
                </li>
            </ul>
        </div>
    </div>
</body>

</html>

Summary

Yes you can inject some Vue into a project built with regular JavaScript or jQuery. It's not all or nothing.

You can pass data between JavaScript and Vue because it you're dealing with JavaScript objects. JavaScript can look at Vue, Vue has access to functions written in the document.

The trick is to 'stay in your lane' -- work with whatever is controlling the element you're changing.

Keep jQuery outside of Vue, it's easier that way.

Files

You can find the files for this tutorial on GitHub:
https://github.com/workingwebsites/vue-jquery-javascript

Top comments (0)