Creating single page applications with Vue.js and PHP.

So I can’t speak to if this is an allowed use of vue.js with PHP but it does work. I created some mini-apps to illustrate how Vue.js can be used as a better jQuery ( or just less verbose ) in PHP applications. I created four mini applications.

  • General – This app just shows how to display different text with binding
  • Shopping Cart – This shows how you could create a shopping cart. Add items from a list.
  • Tasks – This applications allows you to create tasks and edit created tasks.
  • Multi-form – This is an event registration template that allows you to add different attendees.
Showing the menu items of the app

You can find the code for this app in the repository here. Follow along as I explain different sections if you wish. The application is a PHP application so you need to install a PHP server to run it. I used XAMPP as per usual.

General Section

The general application shows how you can bind variables. In the example I bind the page title that says Vue and PHP.

In order to do this I first had to get data. In my main functions.php file I have this function.

function get_home_page_data(){
    $data  = [
        "message" =>"Vue and PHP ",
        "test" => ""
    ];
    return json_encode($data);
}

I call the above function in the index.php file to get the data for my vue app. The message attribute is binded to an HTML element in the index.php file. Once I create my vue instance I added the data from the PHP function above called get_home_page_data().

<script>
    var myObject = new Vue({
        el: '#app',
        data :<?php echo get_home_page_data();?>
    })
</script>

To display the message in HTML I do the following

 <h3 class="text-muted">{{ message }}</h3>

You can add more attributes in the get_home_page_data function and display them on the webpage as shown above. Its that simple. You get a twig template features without any downloads. One thing to note is that vue is imported at the top using

 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>

This might just be the most important thing without you cant use vue.js :(.

Shopping Cart

The shopping cart application shows a list of items and allows the user to add it to a cart. The cart show how many items are added and allows you to preview them.

This application is located in shop.php. The first thing we do is import our global functions file. I didn’t show this before but we do this in all our apps.

include "functions.php";

We also will have added our vue.js script at the head of the page that we take from CDN.

Our vue instance looks like below

    var myObject = new Vue({
        el: '#app',
        data : {
            showModal: false,
            itemsCount : 0,
            products: "",
            cardIds: [],
            "items": <?php echo get_shop_items();?>
        },

We have a showModal variable and an itemsCount which calculates the number of items in our shopping cart. The products variable keeps track of the products we select to be added to our cart. The cardIds is what we use to submit the products in the form. We send the list of selected ids to our back-end application for processing.

The get_shop_items function gets its data from a file which returns an array. We include the file to get the array data in the shop_items function and send that to the get_shop_items function.

function shop_items(){
    $data = include "db_shop.php";
    return $data;
}

function get_shop_items(){
    $data = shop_items();
    return json_encode($data);
}

Once we have our items we can display the list of products using the v-for binding.

<ul class="list-group">
      <li  v-for="item in items" :key="item.id" class="list-group-item clearfix">
      <div class="" style="width:100%; display: inline-block;">
{{ item.name }} <a href="javascript:void(0)" class="btn btn-sm btn-primary float-right" @click="addToCart(item.id)">Add Item</a>
   </div>
</li>
</ul>

Each list item has an addToCart function that allows the user to add that specific item to the cart. In the methods section of your vue instance we have the function

addToCart( id ) {
   console.log(id)
   this.itemsCount++;
   this.cardIds.push(id);
   this.updateProducts(id);
},

We update the itemsCount, cardIds and perform the updateProducts function.

If we wanted to clear our cart we would press the clear cart button. The function that would be executed is shown below.

clearProducts(){
   this.products = "";
   this.itemsCount = 0;
   this.cardIds = [];
}

Basically we clear the variables that are keeping track of any item that we click.

The submit button actually submits the cart. In order to do this we had a hidden form and updated a hidden input with the values we selected from the cart. When we press the submit button the form gets submitted with our selected product ids.

So the hidden form we have is shown below. The v-model binds products variable. So this is what is submitted when we submit the form.

<form action="submit.php?action=shop" method="get" style="display: inline-block;">
     <input name="products" type="hidden" v-model="products">
                <a href="javascript:void(0);" id="show-modal" @click="showModal = true" class="btn btn-primary">View Cart</a>
     <button class="btn btn-lg btn-success" role="button">Submit Cart</button>
</form>

The updateProducts function controls this. The selected card ids array is converted to string so they can be submitted.

updateProducts( id ){
  this.products = this.cardIds.toString();
},

Finally we did some vue.js magic to create a modal. This modal allows us to view the cart items we selected.

 <modal v-if="showModal" @close="showModal = false" v-bind:items="cardIds">

Our element is created using a template and a component. The component is shown below. To see the template you will need to view the full file. Check it our here.

    Vue.component('modal', {
        template: '#modal-template',
        props: ['items'],
        data: function() {
            return {
                "products" : <?php echo get_shop_items();?>
            }
        }
    });

We give the component access to our shop items using PHP. We also pass cardIds from the main vue application to this component. That is what props was used for. We named the passed variable items and in the element we v-bind items to cardIds ensuring we can access it within our component.

When displaying the list of items in our modal we using v-for to display the results in a list.

<ul>
<li  v-for="item in items" :key="item.id">{{ products[item]["name"] }}</li>
</ul>
Modal showing list of items

If there are no items in the list we display a simple message that the list is empty. We use the v-if command for this.

 <span v-if="items.length <=0">No items added to cart</span>

That’s it. We have a little mini shop using a little bit of code.

Tasks

Our task mini app, allows us to create and edit tasks. It also pulls data from PHP which shows minimally how you would begin to integrate with a database.

Our vue instance consists of the current todo items pulled from PHP, updatedToDos which stores all the ids in a form, a message variable which binds to the input form that you enter our task and some other variables which change how our application behaves.

   var myObject = new Vue({
        el: '#app',
        data : {
            message: "",
            updatedToDos : "",
            stale: false,
            showElement: "none",
            items: <?php echo get_todos();?>,
        },

To save a new task we just need to enter some text and press the save button. The save button executes the addToDo function. This function can be seen below.

addToDo() {
   this.addToItems(this.message);
   this.message = "";
},

Basically we add to the items array we created earlier and we then clear the message from the form. If we dig deeper we can see in the addToItems function where we actually push the new items.

addToItems(message){
     var count = Object.keys(this.items).length;
      this.items[count +1 ] = {
             'id' : "nan",
               "item":message,
         };
        this.convertToString();
 },

If we wanted to edit the task we press the edit button. The button calls the editTasks function. All this does is change a variable value.

editTasks(){
   this.showElement = "inline-block";
},
Normal items view

What happens when this button is pressed – the edit button

Edit Task view

How is this done. ( looking at the pictures and asking ) How do we get inputs appearing out of nowhere. Whats even better is if we edit any one of this or all of these and press save the list will change. How awesome is that. 🙂

We can bind style attributes to variables that we created. We can also use computed properties to bind to our elements. Below we use a computed property that works with the showElement variable.

 <span v-bind:style="{display:invertedDisplay}">{{ item.item }}</span>

The function for the computed property invertedDisplay is shown below –

invertedDisplay: function () {
  if( this.showElement == "none"){
       return "inline-block";
    }
      return "none";
},

The showElement variable controls whether the inputs are visible or invisible. When we change the showElement variable we change the display properties associated with it. The invertedDisplay property reverses the showElement display properties. The inputs are first hidden as shown below. Because showElement is by default set to none but we change it when we press the edit button.

 <input type="text" v-bind:style="{display:showElement}" v-model="item.item" style="width: 100%"/>

The saveTasks function takes all tasks items and converts them to string. We can then submit these items in a form.

saveTasks(){
   this.convertToString();
   this.showElement ="none";
}
convertToString(){
    this.updatedToDos = JSON.stringify(this.items);
    this.stale = true;
},

After we convert the ids to string we set showElement to none. This will hide the inputs but show the items in the lists as before.

When adding a task we don’t need to press the save button. We can actually bind an action to the enter keyboard. When enter is pressed the action we selected takes place.

<input style="width: 80%;" v-model="message" v-on:keyup.enter="addToDo()" type="text"
placeholder="Enter a task">

So above we add the v-on to keyup and specify enter. The function we use is the addToDo function. So when the enter key is pressed when the input has focus the function addToDo will be called. Of course the save button works as well to.

Multi Form

So this application was actually supposed to mimic the multi form applications that are created in jQuery. These applications we copy a section of a form multiple times. If you wanted to add multiple attendees you would copy the form multiple times and use an array in the input value to submit and get the data. However using vue.js I implemented the form a bit differently.

Instead of duplicating forms we keep track of the attendees added in a list. So we have one form and we use vue.js to take inputs from that form and store the data in a list.

Attendee Form

We then have a form preview section that shows what the user enters in the form. Whatever is entered in the main form shows up here as well as the list of attendees saved.

Form preview

At the bottom of the form we have a submit form which does what we usually do. The data is submitted and we of course have an hidden input to deal with the attendees data.

By now what we are doing is not special. To add an attendee we just push the values to an array

addAttendee() {
   this.attendees.push({
        "name" : this.aname,
        "email" : this.aemail,
        "status" : this.status
   });
   this.aname = "";
   this.aemail = "";
   this.list = JSON.stringify(this.attendees);
},

That’s the hardest part really. Our hidden input is binded to the list variable. So if we update the list variable we will get those values on form submission.

 <input type="hidden" v-model="list" name="attendeesList">

Submission

To get a better idea of how submitting the data works in PHP you can reference the submit.php file. I used a GET action on all my forms but if it were POST you would just change the function to reflect same. The submit.php files has two main functions – well if statements really.

if( isset($_GET["products"]) && !empty($_GET["products"]) ){
    $ids = explode(',', $_GET["products"]);
    $products = shop_items();
    foreach( $ids as $id ){
        echo $products[$id]["name"]. "<br>";
    }
}

The first deals with the shopping cart. It gets the products you submitted and displays them.

if(isset($_GET["todos"]) && !empty($_GET["todos"])){
    $data = json_decode($_GET["todos"],true);
    foreach($data as $row ){
        if($row["id"] == "nan"){
            echo "create task: " . $row["item"] . "<br>";
        }else{
            echo "update task: " . $row["id"] . " - " . $row["item"] . "<br>";
        }
    }
}

The second deals with the task application. It checks to see if the task is new and needs to be created or if it already exists and just needs an update. When creating tasks using vue.js I put the id as “nan” for new tasks. Old tasks will have ids though.

Conclusion

So that’s some things we can use vue.js for in PHP. We didn’t use jQuery to do these things. We didn’t need additional library’s to implement the popups we created. Have fun using vue.js.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s