VueJs is a light weight progressive web framework for developing interactive web interfaces. Following code example is a product price engine that was built with Vue JS. Basically, this sample code project has functionalities, that are: retrieving all existing products, calculating product cost and provisioning new products. The CRUD operations were handled using a java program. The codes of the java program was not included in here.

Package.json

{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "0.18.0",
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-router": "3.1.3",
    "vuejs-logger": "1.5.3"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.4.0",
    "@vue/cli-plugin-eslint": "~4.4.0",
    "@vue/cli-service": "~4.4.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "vue-template-compiler": "^2.6.11"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

main.js – main javascript file that will initialize the vue js components

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

import VueLogger from 'vuejs-logger';

const options = {
  isEnabled: true,
  logLevel: 'debug',
  stringifyArguments: false,
  showLogLevel: true,
  showMethodName: false,
  separator: '|',
  showConsoleColors: true
};

Vue.use(VueLogger, options);

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: {
    App
  }
});

App.vue – main component

<template>
  <div class="container">
    <PriceEngineApp />
  </div>
</template>

<script>
import PriceEngineApp from "./components/PriceEngineApp.vue";

export default {
  name: "TestPriceEngine",
  components: {
    PriceEngineApp
  }
};
</script>

<style>
@import url(https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css);
</style>

ProductDataService.js – service layer to handle requests from the UI view

import axios from "axios";

const PRICE_ENGINE_API_URL = "http://localhost:8050/testpriceengine";

class ProductDataService {
  retrieveAllProducts() {
    return axios.get(`${PRICE_ENGINE_API_URL}/products`);
  }

  calculateProductCost(product_id, number_of_units) {
    return axios.post(`${PRICE_ENGINE_API_URL}/product/price`, {
      productId: `${product_id}`,
      numberOfUnits: `${number_of_units}`
    })
  }

  provisionProduct(product_name, category, price_per_carton, units_per_carton) {
    return axios.put(`${PRICE_ENGINE_API_URL}/product`, {
      name: `${product_name}`,
      category: `${category}`,
      pricePerCarton: `${price_per_carton}`,
      unitsPerCarton: `${units_per_carton}`
    })
  }
}

export default new ProductDataService();

ListProductsComponent.vue – component for listing all the available products

<template>
  <div class="container">
    <h3>Products</h3>
    <br />
    <div v-if="message" class="alert alert-danger">
      {{ message }}
    </div>
    <div class="container">
      <table class="table">
        <thead>
          <tr>
            <th>Product Name</th>
            <th>Category</th>
            <th>Unit Price</th>
            <th>Carton Price</th>
            <th>Units Per Carton</th>
            <th>Required Units</th>
            <th>Total Price</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="product in products" v-bind:key="product.productId">
            <td>{{ product.name }}</td>
            <td>{{ product.category }}</td>

            <td>Rs. {{ product.productConfig.pricePerUnit }}</td>
            <td>Rs. {{ product.productConfig.pricePerCarton }}</td>
            <td>{{ product.productConfig.unitsPerCarton }}</td>
            <td>
              <button
                class="btn btn-warning"
                v-on:click="decreaseCount(product.productId)"
              >
                -
              </button>

              &nbsp;&nbsp;
              <label :id="'countlbl_' + product.productId">0</label>
              &nbsp;&nbsp;

              <button
                class="btn btn-info"
                v-on:click="increaseCount(product.productId)"
              >
                +
              </button>

              &nbsp;&nbsp;
              <button
                class="btn btn-secondary"
                v-on:click="calculateProductCostClicked(product.productId)"
              >
                Get Price
              </button>
            </td>
            <td>
              Rs. <label :id="'costlbl_' + product.productId">0.00</label>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
import ProductDataService from "../service/ProductDataService";
export default {
  name: "ProductList",
  data() {
    return {
      products: [],
      message: null
    };
  },
  methods: {
    refreshProducts() {
      ProductDataService.retrieveAllProducts()
        .then(response => {
          this.products = response.data;
        })
        .catch(error => {
          this.message =
            "Error code: " +
            error.response.headers["x-test-code"] +
            " | Error message: " +
            error.response.headers["x-test-message"];
          console.error(error);
        });
    },

    calculateProductCostClicked(product_id) {
      var number_of_units = document.getElementById("countlbl_" + product_id)
        .innerHTML;
      ProductDataService.calculateProductCost(product_id, number_of_units)
        .then(response => {
          this.message = null;
          document.getElementById("costlbl_" + product_id).innerHTML =
            response.data.calculatedTotalPrice;
        })
        .catch(error => {
          this.message =
            "Error code: " +
            error.response.headers["x-test-code"] +
            " | Error message: " +
            error.response.headers["x-test-message"];
          document.getElementById("costlbl_" + product_id).innerHTML = "0.00";
          console.error(error);
        });
    },

    decreaseCount(product_id) {
      console.log(document.getElementById("countlbl_" + product_id).innerHTML);
      document.getElementById("countlbl_" + product_id).innerHTML =
        parseInt(document.getElementById("countlbl_" + product_id).innerHTML) -
        1;
      this.message = null;
    },

    increaseCount(product_id) {
      document.getElementById("countlbl_" + product_id).innerHTML =
        parseInt(document.getElementById("countlbl_" + product_id).innerHTML) +
        1;
      this.message = null;
    }
  },
  created() {
    this.refreshProducts();
    this.message = null;
  }
};
</script>

<style></style>

PriceEngineApp.vue – main view component that will display the provision screen and lists the available products

<template>
  <div class="app-root-style">
    <h1 style="color: #f47e47" class="text-center">
      β„™π•£π•šπ•”π•– π”Όπ•Ÿπ•˜π•šπ•Ÿπ•– π”Έπ•‘π•‘π•π•šπ•”π•’π•₯π•šπ• π•Ÿ
    </h1>
    <br />
    <ListProductsComponent></ListProductsComponent>
    <br />
    <br />
    <hr />
    <div class="text-center">
      <button class="btn btn-dark" v-on:click="toggleProvisionComponent()">
        Click to provision products
      </button>
    </div>
    <br />
    <br />
    <ProvisionProductsComponent
      v-if="isShowProvision"
    ></ProvisionProductsComponent>
    <br />
    <br />
    <div class="text-right">
      Developed by Hafeez MarzukΒ©2020
    </div>
  </div>
</template>

<script>
import ListProductsComponent from "./ListProductsComponent";
import ProvisionProductsComponent from "./ProvisionProductsComponent";

export default {
  name: "PriceEngineApp",
  data() {
    return {
      isShowProvision: false
    };
  },
  methods: {
    toggleProvisionComponent() {
      this.isShowProvision = !this.isShowProvision;
    }
  },
  components: {
    ListProductsComponent,
    ProvisionProductsComponent
  }
};
</script>

<style scoped>
.app-root-style {
  background-color: black;
  background-image: radial-gradient(
      white,
      rgba(255, 255, 255, 0.2) 2px,
      transparent 40px
    ),
    radial-gradient(white, rgba(255, 255, 255, 0.15) 1px, transparent 30px),
    radial-gradient(white, rgba(255, 255, 255, 0.1) 2px, transparent 40px),
    radial-gradient(
      rgba(255, 255, 255, 0.4),
      rgba(255, 255, 255, 0.1) 2px,
      transparent 30px
    );
  background-size: 550px 550px, 350px 350px, 250px 250px, 150px 150px;
  background-position: 0 0, 40px 60px, 130px 270px, 70px 100px;
  color: white;
  font-family: "Times New Roman", Times, serif;
}
</style>

ProvisionProductsComponent.vue – component for provisioning the new products

<template>
  <div class="container">
    <h3>Add New Product</h3>
    <br />
    <div v-if="message" class="alert alert-danger">
      {{ message }}
    </div>
    <div class="container">
      <table class="table">
        <tbody>
          <tr>
            <td>Name:</td>
            <td>
              <input v-model="product_name" placeholder="Name of the product" />
            </td>
          </tr>
          <tr>
            <td>Category:</td>
            <td>
              <input
                v-model="product_category"
                placeholder="Product category"
              />
            </td>
          </tr>
          <tr>
            <td>Carton Price:</td>
            <td>
              <input v-model="carton_price" placeholder="Price of a carton" />
            </td>
          </tr>
          <tr>
            <td>Units Per Carton:</td>
            <td>
              <input
                v-model="units_per_carton"
                placeholder="Units in a carton"
              />
            </td>
          </tr>
          <tr>
            <td></td>
            <td>
              <button
                class="btn btn-dark"
                v-on:click="
                  provisionProduct(
                    product_name,
                    product_category,
                    carton_price,
                    units_per_carton
                  )
                "
              >
                Provision
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
import ProductDataService from "../service/ProductDataService";
export default {
  name: "ProductProvision",
  data() {
    return {
      products: [],
      message: null
    };
  },
  methods: {
    provisionProduct(
      product_name,
      category,
      price_per_carton,
      units_per_carton
    ) {
      ProductDataService.provisionProduct(
        product_name,
        category,
        price_per_carton,
        units_per_carton
      )
        .then(response => {
          this.products = response.data;
          console.log(this.products);
          location.reload();
        })
        .catch(error => {
          this.message =
            "Error code: " +
            error.response.headers["x-test-code"] +
            " | Error message: " +
            error.response.headers["x-test-message"];
          console.error(error);
        });
    }
  },
  created() {
    this.message = null;
  }
};
</script>

<style></style>

vue.config.js – main configuration file for the vue js application

module.exports = {
  runtimeCompiler: true
};

babel.config.js – babel configuration was used for compiler purpose

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ]
}