Article image

HOW TO USE LARAVEL BLADE AND VUE.JS COMPONENTS TOGETHER

Laravel -

Sep 16 2019

Dino Numic

Laravel provides Vue.js support out of the box which means that we do not have to create a separate Vue project. Instead, we can write our Vue logic directly in Laravel resources folder. In this article we will look at how we can write and use Vue components inside our blade files. 

Follow this guide if you don’t have Laravel application installed.

Let’s say that that somewhere in our application we want to have a table of all users. We want to have a Laravel blade file which inside calls a Vue component that will perform the process of fetching and displaying users. Sounds good, alright then, let’s get started.

If you don’t already have users table, you can create one now. To be honest, it can be anything you want, but for the sake of this article, we will stick to users table, logic will be the same for any.

php artisan make:migration create_users_table. If you generated Laravel’s default authentication you don’t need to do this.

Next we will create a seeder with a factory for our users table. We need some dummy data to play with.

php artisan make:seeder UserTableSeeder

In default Laravel application UserFactory model is already created. The thing we need to do is to use the factory inside our UserTableSeeder and call the seeder from DatabaseSeeder class.


class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $users = factory(User::class, 100)->create();
    }
}



class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
         $this->call(UsersTableSeeder::class);
    }
}

After this is done, go ahead and run php artisan migrate:fresh –seed. This command will drop and migrate all tables and run all seeders. 

Now let's create a new web route, a user controller, and a view blade file where we will place our user table vue component.


Route::get('/users', 'UserController@index')->name('user.index');

php artisan make:controller UserController


class UserController extends Controller
{
    public function index (Request $request)
    {
        return view('pages.user.index');
    }
}

I created a following view structure but you are free to place it anywhere you want.

@extends('layouts.app')



@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-12">
                <div class="card">
                    <div class="card-header">Users</div>
                    <div class="card-body">
                        Users table will soon be here
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

If you visit http://127.0.0.1:8000/users you should see a following screen.


Now we can start working on our user index vue component. I usually create a folder for each component.

I have added a table where our users will be displayed.


<template>
   <table class="table table-hover">
       <thead>
           <tr>
              <th scope="col">#</th>
                <th scope="col">Name</th>
                <th scope="col">Email</th>
                <th scope="col">Updated At</th>
                <th scope="col">Created At</th>
           </tr>
       </thead>
       <tbody>
           <tr v-for="user in users" :key="user.id">

           </tr>
       </tbody>
   </table>
</template>
<script>
    export default {
        data() {
            return {
                users: []
            }
        },
        created() {
            // TODO ajax request to fetch users
        }
    }
</script>

It is important to tell Vue that our user component exists and that it is available under user-index name.


Vue.component('user-index', require('./components/User/UserIndex.vue').default);

Now we can replace our silly text with our vue component.


<div class="card-body">
    <user-index></user-index>
</div>

After we refresh the page, we can see that it is starting to look like something.

Now we need an ajax request inside our created() method that will fetch the users and populate our users array(). For this we will use axios.

In our UserController let’s add another method that will paginate and return all users.


public function indexJson()
{
    $users = User::paginate(20);
    return UserResource::collection($users);
}

We can create a UserResource by running a simple command. php artisan make:resource UserResource. These resource files will be created in Http\Resources folder. We will modify toArray() method and format timestamp fields.


public function toArray($request)
{
    return [
        'id'    => $this->id,
        'name'  => $this->name,
        'email' =>$this->email,
        'updated_at' => Carbon::parse($this->updated_at)->diffForHumans(),
        'created_at' => Carbon::parse($this->updated_at)->format('m/d/Y'),
    ];
}

diffForHumans() Carbon method will give us a slick and very popular time format such as one hour ago, in two weeks, and etc.

We also need to create a route that will axios call in order to execute the command. This will be an api route placed in api file In your routes folder.


Route::get('/users', 'UserController@indexJson');

Now we can create our axios get request and finish our UserIndex component.


<template>
        <table class="table table-hover">
            <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Name</th>
                    <th scope="col">Email</th>
                    <th scope="col">Updated At</th>
                    <th scope="col">Created At</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(user, index) in users" :key="user.id">
                    <td>{{ index + 1 }}</td>
                    <td>{{ user.name }}</td>
                    <td>{{ user.email }}</td>
                    <td>{{ user.updated_at }}</td>
                    <td>{{ user.created_at }}</td>
                </tr>
            </tbody>
        </table>
</template>
<script>
    export default {
        data() {
            return {
                users: []
            }
        },
        created() {
            axios.get('/api/users')
                .then(response => {
                    this.users = response.data.data;
                })
                .catch(error => {
                    console.log("Error", error)
                })
        }
    }
</script>

This is pretty much it how you can use Vue components inside blade files in the case where you do not have a single page application. Having Vue for handling forms, tables, gives a website a modern look and leaves a good impression on the user.

It is worth mentioning that you can also directly pass php variables as props to Vue components. Lets pass a currently logged user name to our index blade and display some welcoming message.


Our UserController


public function index (Request $request)
{
    $authUser = Auth::user();
    return view('pages.user.index', compact('authUser'));
}

Our user index blade file


<div class="card-body">
    <user-index :auth-user="{{ $authUser }}"></user-index>
</div>

Our UserIndex Vue component


<template>
        <div>
            <h1>Hello, {{ authUser.name }}.</h1>
            <table class="table table-hover">
                <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Name</th>
                    <th scope="col">Email</th>
                    <th scope="col">Updated At</th>
                    <th scope="col">Created At</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="(user, index) in users" :key="user.id">
                    <td>{{ index + 1 }}</td>
                    <td>{{ user.name }}</td>
                    <td>{{ user.email }}</td>
                    <td>{{ user.updated_at }}</td>
                    <td>{{ user.created_at }}</td>
                </tr>
                </tbody>
            </table>
        </div>
</template>
<script>
    export default {
        props: {
            authUser: {
                type: Object
            }
        },
        data() {
            return {
                users: []
            }
        },
        created() {
            axios.get('/api/users')
                .then(response => {
                    this.users = response.data.data;
                })
                .catch(error => {
                    console.log("Error", error)
                })
        }
    }
</script>

This wraps this article. Good luck on making awesome stuff. You have a coders blessing.