Tutorial

Build an Amazon-Like Product Preview App using Vue.js

Draft updated on Invalid Date
Default avatar

By Chris Nwamba

Build an Amazon-Like Product Preview App using Vue.js

This tutorial is out of date and no longer maintained.

Introduction

If you have ever used online stores like Amazon or eBay, you have definitely used the preview feature. It shows you images or videos of the product so you know what to expect before making a purchase.

In this article, we are going to examine how to build a single-page Amazon-like preview app with Vue.js.

What we will build won’t look exactly like the Amazon website, but will exhibit the product preview characteristics.

Prerequisites

To build this app, we are going to use a Node server for the back-end and Vue.js for our front-end. Before we get to work, you need to verify that you have a couple of things installed on your machine:

Building the Front-end

We going to use Vue.js to build the front-end. Vue.js is a progressive JavaScript framework that is quick and easy to use.

Installing Vue.js

You are going to need Vue.js installed on your machine. You can confirm your installation by running:

  1. vue --version

If you get a version number as a result then you have Vue.js installed. If not, it is recommended that you install the Vue CLI by running:

  1. npm install --global vue-cli

To create the frontend server, run the following :

  1. mkdir preview-app
  2. vue init webpack frontend

This creates a Vue example project which we are now going to tweak and adjust.

Installing The Node Modules

We are going to use axios to make get requests from one of our Vue.js components so install it by running the following in the frontend directory:

  1. cd frontend
  2. npm install axios

Creating the Listing Component

This Listing component is responsible for showing all the products we have in the store and adding a link to the view for the product.

To create the Listing component, we run the following:

  1. touch Listing.vue

In the Listing.vue, we need to first import the axios module:

    <script>
    import axios from 'axios'
    //...

And now we use the module to fetch the product listing:

    //...
    export default {
      name: 'Listing',
      data () {
        return {
          products : []
        }
      },
      mounted : function(){
        axios.get('http://localhost:3128/products').
        then( result => {
          console.log( result );
          this.products = result.data;
        })
      }
    }
    </script>

We can see above that once the component is mounted, we make a call to our back-end server to fetch the available products and then assign them to the product data of the component.

The template for the component looks like this:

    <template>
      <div class="listing container">
        <div class="title" style="margin-bottom:40px;">
          <h1>Products on Sale</h1>
        </div>
        <div class="row">
          <div class="col-sm-2">
            <h2>#</h2>
          </div>
          <div class="col-sm-8">
            <h2>PRODUCT NAME</h2>
          </div>
          <div class="col-sm-2">
            <h2>GO TO</h2>
          </div>
        </div>

        <template v-for="product in products">
          <div class="row" style="margin-bottom:20px;">
            <div class="col-sm-2" >
              <p>{{ product.id }}</p>
            </div>
            <div class="col-sm-8">
              <p>{{ product.name }}</p>
            </div>
            <div class="col-sm-2">
              <router-link :to="{path: '/product/'+product.id }">View Product</router-link>
            </div>
          </div>
        </template>
      </div>
    </template>

In the template above, we list out the products as divs and add an action button that takes you to the single product page itself.

Creating the Preview Component

The Preview component is responsible for displaying data and images related to the selected product from the previous view. When the component is created, we make a get request to the backend server to fetch all the data for the particular id and then display the media in the form of a carousel on the right side of the screen.

Create the Preview.vue file by running :

  1. touch Preview.vue

In the Vue.js file, we first import the axios module:

    <script>
    import axios from 'axios'
    //...

Now, we build the component:

    //...
    export default {
      name: 'Preview',
      data () {
        return {
          media :[],
          product_name : "",
          product_desc : "",
          product_price : ""
        }
      },
      mounted : function(){
        // now we get all the related infomation for the particular product id
        axios.get(`http://localhost:3128/getProductInfo/${this.$route.params.id}`)
        .then( res => {
          this.media = res.data.media;
          this.product_name = res.data.product_name;
          this.product_desc = res.data.product_desc;
          this.product_price = res.data.product_price;

        })
      },
      methods : {
        initializePlayer : function(){
          console.log('here')
          var cld = cloudinary.Cloudinary.new({ cloud_name: "CLOUDINARY_CLOUD_NAME", secure: true});
          var demoplayer = cld.videoPlayer('video-player');
        }
      }
    </script>

After the post request is made, the model is updated with the data that was returned as a JSON response on the backend.

Our view has a template that looks as follows:

    <template>
      <div class="preview">
        <div class="row">
          <div class="col-sm-6">
            <!--  this part will contain the product info -->
            <h1> {{ product_name }} </h1>
            <div>
              <p> {{ product_desc }} </p>
              <p> Price : ${{ product_price }} </p>
            </div>
          </div>
          <div class="col-sm-6">
            <!--  this part will contain the images -->
            <div id="demo" class="carousel slide" data-ride="carousel">
              <!-- Indicators -->
              <ul class="carousel-indicators">
                <template v-for="single_media in media">
                  <template v-if="single_media.id == 0">
                    <li data-target="#demo" v-bind:data-slide-to="single_media.id" class="active"></li>
                  </template>
                  <template v-else>
                    <li data-target="#demo" v-bind:data-slide-to="single_media.id"></li>
                  </template>
                </template>
                <!-- <li data-target="#demo" data-slide-to="0" class="active"></li>
                <li data-target="#demo" data-slide-to="2"></li> -->
              </ul>
              <!-- The slideshow -->
              <div class="carousel-inner">
                <template v-for="single_media in media">
                  <template v-if="single_media.id == 0">
                    <div class="carousel-item active">
                      <template v-if="single_media.type == 'image'">
                        <img class="img-responsive single-image" v-bind:src="single_media.url"/>
                      </template>
                      <template v-else>
                       <video
                        id="video-player"
                        controls
                        class="single-image cld-video-player cld-video-player-skin-dark"
                        v-bind:data-cld-source="single_media.url"
                        >
                        </video>
                      </template>
                    </div>
                  </template>
                  <template v-else>
                    <div class="carousel-item">
                      <template v-if="single_media.type == 'image'">
                        <img class="img-responsive single-image" v-bind:src="single_media.url"/>
                      </template>
                      <template v-else>
                        <video
                        id="video-player"
                        controls
                        class="single-image cld-video-player cld-video-player-skin-dark"
                        v-bind:data-cld-source="single_media.url"
                        >
                        </video>
                      </template>
                    </div>
                  </template>
                </template>
              </div>
              <!-- Left and right controls -->
              <a class="carobbusel-control-prev" href="#demo" data-slide="prev">
                <span class="carousel-control-prev-icon"></span>
              </a>
              <a class="carousel-control-next" href="#demo" data-slide="next"  v-on:click="initializePlayer()">
                <span class="carousel-control-next-icon"></span>
              </a>
            </div>
          </div>
        </div>

      </div>
    </template>

In the template above, what we want to achieve is to display the media for the particular product. If you take a look at when we built the component, we make a request to the backend and then send the response to the Vue component.

We need to know if the media being displayed is an image or a video. So we check in the template;

    //..
    <template v-if="single_media.type == 'image'">
      <img class="img-responsive single-image" v-bind:src="single_media.url"/>
    </template>
    <template v-else>
     <video
      id="video-player"
      controls
      class="single-image cld-video-player cld-video-player-skin-dark"
      v-bind:data-cld-source="single_media.url"
      >
      </video>
    </template>
    //..

If it has type of image, we display the image in the carousel but if type is a video, we use the Cloudinary Video Player to display the video. To initialize the video player, we add v-on:click event to the > button.

Once the button is clicked, the video player is initialized with the video.

PS: Cloudinary’s video player also plays videos by tags and playing playlists. You can read more about it here.

The preview view has some scoped styling as follows:

    <style scoped>
      h1, h2 {
        font-weight: normal;
      }
      ul {
        list-style-type: none;
        padding: 0;
      }
      li {
        display: inline-block;
        margin: 0 10px;
      }
      a {
        color: #42b983;
      }
      .carousel-inner{
        height : 500px;
      }
      .carousel-item{
        height : 100%;
      }
      .single-image{
        width : 100%;
        height: 100%;
        object-fit : fill;
      }
      #demo{
        margin-left: 30px;
        margin-right: 30px;
      }
    </style>

Linking Components

To allow for flow from one component to another, Vue has what is called the vue-router. Open the frontend/src/router/index.js file and edit it to look like this:

    // frontent/src/router/index.js

    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    import Listing from '@/components/Listing'
    import Preview from '@/components/Preview'

    Vue.use(Router)

    export default new Router({
      routes: [
        {
          path: '/',
          name: 'Listing',
          component: Listing
        },
        {
          path: '/product/:id',
          name: 'Product',
          component: Preview
        }
      ]
    })

This specifies the available routes for the application. Earlier on in the components, we used <router-link> to move from the Listing component to the Preview component and this is the file that handles what you get. You can add a lot more options when creating routers. To read more about it, head over here.

Building the Back-end

To build our back-end, we need to change the directory to the root directory of our application:

  1. cd preview-app

And then install the node modules:

  1. npm install cors express body-parser dotenv request connect-multiparty cloudinary

Once this is done, you have successfully installed all the modules necessary for you to build the project.

Create a server.js file

Now we need to create a file that will contain the instructions for our server to work. In your video-suggestion directory:

  1. touch server.js

This will be the start-up file that will be referenced when your server is running.

In your server.js file, you need to

Import the node modules

    require('dotenv').config()
    const cors       = require('cors')
    const express    = require('express')
    const bodyParser = require('body-parser')
    const multipart  = require('connect-multiparty')
    const request    = require('request')
    const cloudinary = require('cloudinary')

    //...

Once you have imported your node modules, you can then use them freely all through your script.

Create your express app

Now we create our express app instance by adding the following to the server.js

    //...

    const app = express()

    //...

Load the middlewares

We load the middlewares in our server.js by adding the following

    //...

    app.use(cors())
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    const multipartMiddleware = multipart();

    //...

Here, we set our app to use cors. We also instructed the app to parse the requests in JSON format.

Configure the Cloudinary Client

We need to configure our Cloudinary client using your CLOUD_NAME, API_KEY and API_SECRET

    //...

    cloudinary.config({
        cloud_name: 'CLOUDINARY_CLOUD_NAME',
        api_key: 'CLOUDINARY_API_KEY',
        api_secret: 'CLOUDINARY_API_SECRET'
    });

    //...

Once this is done, then we have successfully configured our Cloudinary client.

Create app routes

Our backend server is very simple, it’s an express web server with two major routes:

  • /products - Lists all the products available for sale.
  • /getProductInfo - Returns data for the selected product.
    //...
    app.get('/products', multipartMiddleware, function(req, res){
      return res.json([
        {id: '1', name: 'UltraLight Mechanical Keyboard'},
        {id: '121', name: 'IPhone X'},
        {id: '23', name: 'Tesla S'},
        {id: '42', name: 'Work Shoes'}
      ]);
    });

    app.get('/getProductInfo/:id', multipartMiddleware, function(req, res){
      console.log( req.params.id );
      return res.json({
        media:        [
          {
            id:       '0',
            type:     'image',
            url:      'example.jpeg'
          },
          [...]
          {
            id:       '3',
            type:     'video',
            url:      'example.mp4'
          },
        ],
        product_name: 'Ultra Thin Mechanical Keyboard',
        product_desc: 'This keyboard gives you the clack to your click',
        product_price: '200'
      })
    });

    //...

In the above, we see the routes returning responses in JSON format for it to be further used at the frontend. You may have observed that a lot (all) of the data returned to the user was static. In a real-world application, you would return dynamic data to the user.

The /productInfo route accepts the id of your product so that is what you would use to identify what data to serve instead of just returning static JSON data. In other words, you can make further queries to your database or cloud storage to fetch the information and return the data in the format used above.

Configure Application Port

Now we set the port we want the app to listen on:

    [...]

    let port = 3128 || process.env.PORT;

    app.listen(port, function () {
      console.log('App listening on port ' + port + '!');
    });

Conclusion

In this article, we have seen how to leverage Cloudinary’s image and video capabilities using Vue.js to build an Amazon-like preview app for products.

Here is a link to the GitHub repository for more references.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Chris Nwamba

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel