Click to share! ⬇️

How To Use VueJS With jQuery

In the last article we turned the reply form into a Vue component and saw how nice it was to have reactive data properties to handle editing and updating of a reply. In this article we can build on that Reply component and turn the delete function into an ajax powered version as well. In addition, we’ll see how you can still make use of jQuery in concert with VueJS for adding very simple jQuery animation type actions to your component. The end result should be a reply that gets deleted with no page refresh, and real time feedback and page updates for the end user.


From HTML Form to Vue Method

The delete function works just fine as we have it now but we would rather use ajax and our Vue component to create that real time effect on the page. When skipping JavaScript, we use a full html form with a button nested inside of it to complete the delete function like so.

reply.blade.php


<div class="panel-footer level">
    <button @click="editing = true" class="btn btn-xs mr-1">Edit</button>
    <form method="POST" action="/replies/{{$reply->id}}">
        {{ csrf_field() }}
        {{ method_field('DELETE') }}
        <button class="btn btn-danger btn-xs">Delete Reply</button>
    </form>
</div>

With a little work on our Vue Instance and some tidying up of the destroy() method on the RepliesController, we’ll be able to use this simple markup for the delete button in the view.


<div class="panel-footer level">
    <button @click="editing = true" class="btn btn-xs mr-1">Edit</button>
    <button @click="destroy" class="btn btn-xs btn-danger mr-1">Delete</button>
</div>

Adding The destroy() method

We’ll need to add a destroy() method to the Vue instance since we are trying to trigger that method when the delete button is clicked. When running Vue in development mode, it will even alert us that we need to take care of this. When we visit a page with a reply component – we get the error in the console of: “[Vue warn]: Property or method “destroy” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.”
method not defined on vue instance


Boot Up The File Watcher

We are now going to start working with the Vue component so we need to boot up the file watcher. We’ll run it with yarn run watch-poll.
yarn run watch-poll


Updating Reply.vue

Here we add the destroy() method to our Vue instance.


<script>
    export default {
        props: ['attributes'],

        data() {
            return {
                editing: false,
                body: this.attributes.body
            };
        },

        methods: {
            update() {
                axios.patch('/replies/' + this.attributes.id, {
                    body: this.body
                });
                this.editing = false;
                flash('Updated!');
            },

            destroy() {
                axios.delete('/replies/' + this.attributes.id);
                flash('Your reply is now deleted!');
            }
        }
    };
</script>

An odd bug

Trying to delete a reply is actually now deleting the thread itself. The destroy() method on the RepliesController needs to be fixed.


expectsJson() in controller methods

Since we have removed the form in the view, and we are now sending and ajax request to the server, the method handling that ajax request needs to be updated to handle this action.


public function destroy(Reply $reply)
{
    $this->authorize('update', $reply);

    $reply->delete();
    
    //  if there is an ajax request, do not redirect
    if (request()->expectsJson()) {
        return response(['status' => 'Reply deleted']);
    }
    
    return back();
}

Now, the method is able to determine if there is an ajax request in play here. If so, we just return right away with no redirect. We also send back a status response of ‘Reply deleted’. Testing this out in the browser seems to have fixed this as we see here. We click the delete button, and when we inspect the headers, we see the DELETE request was made to http://forum.io/replies/6 and the status is 200 ok. Clicking on the “response” tab also shows the message of {“status”:”Reply deleted”}.
chrome developer tools headers


jQuery To The Rescue

There are times when you just want a simple one liner to update something on the page. For this type of thing, jQuery is still hard to beat. Right now, when the delete button is clicked, the reply is deleted from the database. There is no page reload however since the delete was completed via ajax. Therefore, the reply is still on the page. Ideally, it should really disappear once it is deleted. We can update the destroy() method in the Vue instance to fix this. The highlighted code will simply fade out the element over the course of 1 second, then trigger a flash message once complete.


<script>
    export default {
        props: ['attributes'],

        data() {
            return {
                editing: false,
                body: this.attributes.body
            };
        },

        methods: {
            update() {
                axios.patch('/replies/' + this.attributes.id, {
                    body: this.body
                });
                this.editing = false;
                flash('Updated!');
            },

            destroy() {
                axios.delete('/replies/' + this.attributes.id);

                $(this.$el).fadeOut(1000, () => {
                    flash('Your reply is now deleted!');
                });
            }
        }
    };
</script>

Looks pretty cool!
VueJS With jQuery


What About CSRF Protection?

You might be wondering, well since we got rid of the form which contained a CSRF token for protection, is this new approach less secure? In fact it is not because Laravel took care of this for you in the bootstrap.js file. If you inspect that file, you’ll find this snippet with the comments explaining exactly what is happening.

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

How To Use VueJS With jQuery Summary

This was a fun and quick little tutorial that had us swapping out a form based button for a delete request for a Vue form and Axios powered ajax solution with a touch of jQuery thrown in for good measure. Don’t forget, you’ll need to update the controller method in Laravel to accomodate the ajax request, and you saw how we did that with the expectsJson() method.

Click to share! ⬇️