Part 2: How to build a job board with vue js and the Laravel 5.5 API ?

Commissioning the back end series

Created on: March 03, 2018

Updated on: March 03, 2018

The best way to begin building a front end / back end application is to set up the API in the first instance. So that you have the best chance in trying to figure out how you want the consumers (users) of your web development services application to consume the content that you are providing.

The front end is where you will need to output the API in its visual form. In our case we will set up a new view in order to accomplish this.

As a reminder, in part 1, we learn't how to build our back end architecture using Laravel 5.5. This included setting up seeder files and seeding our database, setting up our models, controllers and setting up our routes file in a RESTFUL manner.

Today, we will start our set up of the front end view where we will implement view model binding, component and template driven development within the web development services realm.

How to set up the initial view

We need to set up a folder that will contain a parent blade file that will contain the entire HTML mark-ups.

This parent blade file that will be used as a basis for inheritance and the child blade files will inherit the layout from this file.

Master blade file

Create a new folder called layouts underneath the views directory.

layouts/master.blade.php

master.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Job Board</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
</head>

<body>

@yield('content')

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

</body>
</html>

Notice how we a link to our bootstrap css file, this will help us to create basic bootstrap components using css.

And we have a link to our minified version of vuejs and axios. We will use axios later on to make/get requests to fetch our jobs data from the backend.

Jobs blade file

We will now turn our attention to our child blade file which in this case will be called jobs.blade.php.

Underneath the views directory, create a new file called jobs.blade.php.

views/jobs.blade.php

@extends ('layouts.master')

@section('meta-title', 'Latest Jobs')

@section('content')

Notice how we have an extends section, this is where our blade inheritance comes in and we inherit our master blade file from the layouts folder. We also have a title and a content section and this will be the area in which we will build up our table.

Before we do that, we need to think about creating our initial div that will contain our app.

Jobs table

Within the above mentioned jobs blade file create a div named app and underneath it create a H1 title within the content section.

views/jobs.blade.php

@extends ('layouts.master')

@section('meta-title', 'Latest Jobs')

@section('content')

<div id="app">
    <h1>Job Board</h1>

</div><!-- /#app -->

@endsection

Now that we have created our first h1 title within our div we need to add the jobboard table rows and definitions. We are going to create a job listings page and this will contain a table with job rows and definitions.

Underneath the h1 we just created within the jobs.blade.php add the following table headings and rows.

jobs.blade.php

<div id="app">
    <h1>Job Board</h1>
    <table class="table table-striped">
        <tr>
            <th>#</th>
            <th>Reference</th>
            <th>Title</th>
            <th>Type</th>
            <th>Description</th>
            <th>Employer</th>
            <th>Location</th>
            <th>Salary</th>
            <th>Post Date</th>
        </tr>

    </table><!-- /.table -->

</div><!-- /#app -->

Lets have a look at our jobs blade file in context

views/jobs.blade.php

@extends ('layouts.master')

@section('meta-title', 'Latest Jobs')

@section('content')

<div id="app">
    <h1>Job Board</h1>
    <table class="table table-striped">
        <tr>
            <th>#</th>
            <th>Reference</th>
            <th>Title</th>
            <th>Type</th>
            <th>Description</th>
            <th>Employer</th>
            <th>Location</th>
            <th>Salary</th>
            <th>Post Date</th>
        </tr>

    </table><!-- /.table -->  

</div><!-- /#app -->

@endsection

We have created our jobs table, we now need to set up a special type of for loop within vue js. It will fetch the jobs from the job model and it will place them within the table.

Check out the following link to see what a v-for loop does

v-for link

We need to add the following code:

<tr v-for="job in jobs" is="job" :job="job"></tr>

to the end of the table row.

Let's have a look at our code in context.

views/jobs.blade.php

@extends ('layouts.master')

@section('meta-title', 'Latest Jobs')

@section('content')

<div id="app">
    <h1>Job Board</h1>
    <table class="table table-striped">
        <tr>
            <th>#</th>
            <th>Reference</th>
            <th>Title</th>
            <th>Type</th>
            <th>Description</th>
            <th>Employer</th>
            <th>Location</th>
            <th>Salary</th>
            <th>Post Date</th>
        </tr>
        <tr v-for="job in jobs" is="job" :job="job"></tr>

    </table><!-- /.table -->  

</div><!-- /#app -->

@endsection

Template

We now need to think about creating a template within our web development services code. Templates help us to reuse our code so that we are not repeating ourselves all the time.

Underneath the closure of our div named app create a new template called template-job-raw and make sure that the fields are identical to the fields you set up in part 1 of this tutorial.

<template id="template-job-raw">
    <tr>
        <td>
            {{job.id}}
        </td>
        <td>
            {{ job.reference }}
        </td>
        <td>
            {{ job.title }}
        </td>
        <td>
            {{ job.type }}
        </td>
        <td>
            {{ job.description }}
        </td>
        <td>
            {{ job.location }}
        </td>
        <td>
            {{ job.employer }}
        </td>
        <td>
            {{ job.salary }}
        </td>
        <td>
            {{ job.post_date }}
        </td>
    </tr>

</template><!-- /#template-job-raw -->

We have successfully created our views for our job board, but sadly we can’t see anything if we attempt to the page on our website.

The reason why this is happening and that is because we have not set up our vue component as a script on the master blade file.

Vue Component

We need to set up our vue component on our master.blade.php file.

Create a new script underneath the axios script and add the code for a new component.

vue component

<script type="text/javascript">
    Vue.component('job' , {
        template: "#template-job-raw",
        props:  ['job' ]
    });

    var  vm = new  Vue({
        el: '#app' ,
        data:  {
        jobs:  []
    },
    mounted: function (){
        this.fetchJobs()
    },
        methods: {
            fetchJobs: function() {
                var vm = this;
                axios.get('/api/jobs')
                    .then(function (response) {
                        // set data on vm
                        var jobsReady = response.data.map(function (job) {
                            job.editing = false;
                            return job
                        })
                        Vue.set(vm, 'jobs', jobsReady)
                    });
                }

        }
    })
</script>

Seen in context

layouts/master.blade.php


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Job Board</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
</head>

<body>

@yield('content')

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    Vue.component('job' , {
        template: "#template-job-raw",
        props:  ['job' ]
    });

    var  vm = new  Vue({
        el: '#app' ,
        data:  {
        jobs:  []
    },
    mounted: function (){
        this.fetchJobs()
    },
        methods: {
            fetchJobs: function() {
                var vm = this;
                axios.get('/api/jobs')
                    .then(function (response) {
                        // set data on vm
                        var jobsReady = response.data.map(function (job) {
                            job.editing = false;
                            return job
                        })
                        Vue.set(vm, 'jobs', jobsReady)
                    });
                }

        }
    })
</script>

</body>
</html>

<div id="app">
    <h1>Job Board</h1>
    <table class="table table-striped">
        <tr>
            <th>#</th>
            <th>Reference</th>
            <th>Title</th>
            <th>Type</th>
            <th>Description</th>
            <th>Employer</th>
            <th>Location</th>
            <th>Salary</th>
            <th>Post Date</th>
        </tr>
        <tr v-for="job in jobs" is="job" :job="job"></tr>
    </table><!-- /.table -->

</div><!-- /#app -->

<template id="template-job-raw">
    <tr>
        <td>
            {{job.id}}
        </td>
        <td>
            {{ job.reference }}
        </td>
        <td>
            {{ job.title }}
        </td>
        <td>
            {{ job.type }}
        </td>
        <td>
            {{ job.description }}
        </td>
        <td>
            {{ job.location }}
        </td>
        <td>
            {{ job.employer }}
        </td>
        <td>
            {{ job.salary }}
        </td>
        <td>
            {{ job.post_date }}
        </td>

    </tr>

</template><!-- /#template-job-raw -->

Explanation

We are initialising our vue component and this is called job, underneath this we have our template that we created earlier. And notice that we are passing our job as a prop.

We initialise our Vue and this is binded to our div called app, notice that we have the jobs within an array notation.

We have a fetchJobs method that is activated as soon as the vue instance is mounted and we then have the fetchJobs method that uses axios to fetch the jobs and this is then received within a response.

The response returns the jobs and this is bound to the vue instance.

Now open up your browser and type jobboard.dev and notice that you have a listing of all the jobs pulled from the database.

Buttons

Edit and delete buttons

We need to create buttons so that if a user wishes to manipulate our data they are able to do so at ease.

We intend to place our edit and delete within our template over on the far side to the left of our post_date field.


<div id="app">
    <h1>Job Board</h1>
    <table class="table table-striped">
        <tr>
            <th>#</th>
            <th>Reference</th>
            <th>Title</th>
            <th>Type</th>
            <th>Description</th>
            <th>Employer</th>
            <th>Location</th>
            <th>Salary</th>
            <th>Post Date</th>
        </tr>
        <tr v-for="job in jobs" is="job" :job="job"></tr>
    </table><!-- /.table -->

</div><!-- /#app -->

<template id="template-job-raw">
    <tr>
        <td>
            {{job.id}}
        </td>
        <td>
            {{ job.reference }}
        </td>
        <td>
            {{ job.title }}
        </td>
        <td>
            {{ job.type }}
        </td>
        <td>
            {{ job.description }}
        </td>
        <td>
            {{ job.location }}
        </td>
        <td>
            {{ job.employer }}
        </td>
        <td>
            {{ job.salary }}
        </td>
        <td>
            {{ job.post_date }}
        </td>

        <td>
            <div class="btn-group" v-if="!job.editing">
                <button @click="editJob(job)" class="btn btn-default">Edit</button>
                <button @click="deleteJob(job)" class="btn btn-danger">Delete</button>
            </div>

 </td>  

    </tr>

</template><!-- /#template-job-raw -->

Notice how we are now using a v-if statement and these are used to determine if the button has been pressed or not.

Check out how v-if works here:

v-if conditional link

In addition to this we have an @click function and this is a listener that is used to determine if the user has clicked on the button or not.

In our case we are using it to check to see if the user has either clicked on edit, delete or save buttons.

These buttons will invoke their own methods and we will create these methods within part 3 of our tutorial.

You can find out more about @click within this stack overflow post listed here:

stack overflow link

Template Input fields

At the moment, our buttons are shown on the table but they don’t actually do anything. Our aim is that if the users presses the edit button we would like it to show and input field so that the user can update the field accordingly.

The delete button won’t have this functionality though its job is to delete a job and we will perform this within part 3 of this tutorial.

However, lets concentrate on the edit button

If the user selects the edit button this will invoke an editJob function and it will activate a new function call the Update job function. We will talk about these functions in more depth in part 3.

In the meantime we will add a v-if statement to a series of fields listed below:

title type description location employer salary post_date

The span class will be used with a velse conditional and this will be activated when the user wishes to amend a field.

Please amend your template file to include this v-if else statment as illustrated in the template file listed below:

template

<template id="template-job-raw">
        <tr>
            <td>
                @{{ job.id }}
            </td>
            <td>
                @{{ job.reference }}
            </td>
            <td>
                <input v-if="job.editing" v-model="job.title" class="form-control">
                </input>
                <span v-else>
                @{{ job.title }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.type" class="form-control">
                </input>
                <span v-else>
                 @{{ job.type }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.description" class="form-control">
                </input>
                <span v-else>
                 @{{ job.description }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.location" class="form-control">
                </input>
                <span v-else>
                @{{ job.location }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.employer" class="form-control">
                </input>
                <span v-else>
                @{{ job.employer }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.salary" class="form-control">
                </input>
                <span v-else>
                @{{ job.salary }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.post_date" class="form-control">
                </input>
                <span v-else>
                @{{ job.post_date }}
            </span>

            </td>

            <td>
                <div class="btn-group" v-if="!job.editing">
                    <button @click="editJob(job)" class="btn btn-default">Edit</button>
                    <button @click="deleteJob(job)" class="btn btn-danger">Delete</button>
                </div>

            </td>

        </tr>

    </template><!-- /#template-job-raw -->

Update, Save and Cancel buttons

It is good web development services programming practice to provide options to the user if they want to cancel what they are doing. In our case these will be added if the user selects the edit button.

When this happens the user can amend the fields or cancel them, as you may be aware these buttons won’t do anything right now but we are placing them there so that they will invoke the update, cancel or save methods.

buttons snippet

<div class="btn-group" v-else>
                    <button v-if="job.id" class="btn btn-primary" @click="updateJob(job)">Update</button>
                    <button v-else class="btn btn-success" @click="storeJob(job)">Save</button>
                    <button @click="job.editing=false" class="btn btn-default">Cancel</button>
                </div>

Template seen in context

 <template id="template-job-raw">
        <tr>
            <td>
                @{{ job.id }}
            </td>
            <td>
                @{{ job.reference }}
            </td>
            <td>
                <input v-if="job.editing" v-model="job.title" class="form-control">
                </input>
                <span v-else>
                @{{ job.title }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.type" class="form-control">
                </input>
                <span v-else>
                 @{{ job.type }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.description" class="form-control">
                </input>
                <span v-else>
                 @{{ job.description }}
            </span>

            </td>
            <td>
                <input v-if="job.editing" v-model="job.location" class="form-control">
                </input>
                <span v-else>
                @{{ job.location }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.employer" class="form-control">
                </input>
                <span v-else>
                @{{ job.employer }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.salary" class="form-control">
                </input>
                <span v-else>
                @{{ job.salary }}
            </span>
            </td>
            <td>
                <input v-if="job.editing" v-model="job.post_date" class="form-control">
                </input>
                <span v-else>
                @{{ job.post_date }}
            </span>

            </td>

            <td>
                <div class="btn-group" v-if="!job.editing">
                    <button @click="editJob(job)" class="btn btn-default">Edit</button>
                    <button @click="deleteJob(job)" class="btn btn-danger">Delete</button>
                </div>
                <div class="btn-group" v-else>
                    <button v-if="job.id" class="btn btn-primary" @click="updateJob(job)">Update</button>
                    <button v-else class="btn btn-success" @click="storeJob(job)">Save</button>
                    <button @click="job.editing=false" class="btn btn-default">Cancel</button>
                </div>

            </td>

        </tr>

    </template><!-- /#template-job-raw -->

At the moment, we have 3 different buttons that will invoke the following methods:

  1. Edit button -> editJob
  2. Delete button -> deleteJob
  3. Save button -> saveJob
  4. Cancel -> sets editing flag to false

Today we learn't how to implement the front end architecture by creating the table, buttons and the template that are used as a means to providing a pathway for the backend api to communicate with the front end.

Wiring up a back end API with a front end application doesn't have to be complicated.

Developing API's require careful planning and scrupulous documentation.

Application development within the web development services world requires the basic understanding on how you can knit together the front and back ends.

We will move on to the next blog post where we will wire up our development application to ensure that our jobs appear in a list that is served up by the web server to the browser.

If you have any questions or queries regarding how to set up front end and back end applications please drop us a line within the discuss comments or contact us at: Ormrepo link