Build a Shopping Cart with Vue, Vuex & Vue Material Design

Build a Shopping Cart with Vue, Vuex & Vue Material Design


In this tutorial, we will be building a shopping cart with Vue and Vue-material-design. In the course of this article, you will learn how to use Vuex and Vue material design In a Vue application by building a shopping cart.

You can check Live demo &  source code if you want to refer to it or take a peek as we get started.

Shopping cart with vue – video demo

Requirements

To get VueJs up and running we need to have the following installed on our computer.

Before we kick off

Learn Vue.js and modern, cutting-edge front-end technologies from core-team members and industry experts with our premium tutorials and video courses on VueSchool.io.

Click here to Browse all Courses on VueSchool.io

Prerequisites

Now let start by installing Vue Cli

npm install -g vue-cli

This command will install VueJS globally.

Now that we have installed Vue in our system, we can now create a Vue project. The command below will create a Vue project, and we are going to select a manual setup that provides more options that are likely needed for more production-oriented projects, and we will going to use Vuex.

Vue create shopping-cart
?Please pick a preset
  default
> Manually

Don’t forget to select Vuex while setting up the project, Our Vue application is now ready for use. Run the command below and open the following URL in your browser.

npm run serve

If the command runs successfully, open localhost:8080 in your browser and you will see a page like this picture below:

We are going to add our Vue material that we will use to build UI for the project. Run the command below and add the Vue material dependencies to our project.

npm install vue-material --save

Once the installation is done, add the following in main.js file.

import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.min.css'

Vue.use(VueMaterial)

Now our app is ready and it time to code. But first, we are going to start by setting up the data that we are going to use in building our project. The data will be stored in the store.js file.

Why store?

A “store” is basically a container that holds your application state. and it is Vuex.

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
state: {}
mutations: {},
actions: {},
modules: {},
});

The above code is how the store.js file looks and we are going to make use state, getters mutations, and action.

state: {
    products: [
      {
        id: 1,
        name: "Samsung Galaxy A8 Spy Phone",
        image:
          "https://www.mobilitaria.com/wp-content/uploads/2019/10/Samsung-Galaxy-A8-Spy-Phone.jpg",
        price: 340,
      },

      {
        id: 2,
        name: "Asus Rog Phone",
        image:
          "https://i.gadgets360cdn.com/products/large/1543479620_635_asus_rog_phone_db.jpg",
        price: 500,
      },

      {
        id: 3,
        name: "Cat Phone",
        image:
          "https://www.catphones.com/wp-content/uploads/2018/08/cat-s41-front.png",
        price: 600,
      },

      {
        id: 4,
        name: "Trainer Socks Black",
        image:
          "https://schoolkits.ng/wp-content/uploads/2019/08/Trainer-Socks-Black.jpg",
        price: 700,
      },
    ],

    StoreCart: [],
  },

The state: {} property, holds two arrays the product and the storeCart.

The product array contains details about each product.

The storeCart array is empty because it is where are going to store each item a user add to cart.

getters: {
    products: (state) => state.products,
    StoreCart: (state) => state.StoreCart,
  },

Getters helps us access the data in the state.

mutations: {
    ADD_Item(state, id) {
      state.StoreCart.push(id);
    },

    REMOVE_Item(state, index) {
      state.StoreCart.splice(index, 1);
  },
},

In mutation, we created two functions. The add_item() and the remove_items. The add_item updates the storeCart with products and the remove_cart removes item from the storeCart.

 actions: {
    addItem(context, id) {
      context.commit("ADD_Item", id);
    },

    removeItem(context, index) {
      context.commit("REMOVE_Item", index);
    },
  },

Instead of mutating the state, actions commit mutations.

Just as the above says, instead of just mutating the state, we are going to use the actions to commit mutation before using it.

Components

Components are reusable blocks of code that can have both structure and functionality. They help create a more modular and maintainable codebase.

Vue.js components always end with a .vue just as we have .html and .css when creating Html or CSS file.

App.vue component comes with Vuejs when creating a Vue project as a root component. Through the App.vue component we can render other components we need in our project, and it is also described as parent components.

Now that we understand what the Vue component is and how to create it, we are going to create our navbar component. In the component folder, delete the Hello-word component and create the Navbar.vue components and add the below code.

<template>

</template>

<script>

</script>

<style lang="scss" scoped>

</style>

If you notice, the code above is divided into three section:

The <template></template> section that holds all the html tags for the component.

The <script></script> section that holds all the javascript code for each component.

The <style lang="scss" scoped></style> section that holds all the style for each component and the scoped attribute stops the style from applying to other components but applies to elements of the current component only.

Now let code.

<template>
  <div class="page-container">
    <md-app>
      <md-app-toolbar class="md-primary">
        <h3 class="md-title">Shopping Cart</h3>
      </md-app-toolbar>
    </md-app>
  </div>
</template>
<style lang="scss" scoped>
.md-app {
  max-height: 50vh;
  border: 1px solid rgba(rgb(0, 0, 0), 0.12);
  background: linear-gradient(-90deg, #6a79cf, #1627c0);
  color: #ffffff;
}
</style>

<script>
export default {
  name: "Navbar"
};
</script>

In the <template></template> we start by creating a div with class=”page container” and <md-app></md-app> tag which wrapper our navigation bar. The <md-app></md-app> is a Vue material design syntax.

In the <script></script> we use the export default statement to indicate that the module is set for export and can be imported and used in another module. Inside the export default, we specify the name of our project name:"Navbar" and the value we specify for the name, will be used to import this component in other components.

In the <style></style> we just add some Ul to our navbar.

In our App.vue component we are going to import Navbar so we can output our design But first remove the existing code in the template tag and leave just the <div id="app"></div>. In the <script></script> tag, remove the contents of the data() function and remove everything in the <style></style>. Now let import our Navbar components.

<template>
  <div id="app">

    <Navbar />

  </div>
</template>

<script>

import Navbar from "./components/Navbar.vue";

export default {
  name: "app",

  components: {
    Navbar
  }

};
</script>

<style lang="scss">
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons");
#app {
  font-family: "Roboto", sans-serif;
  text-align: center;
}
</style>

If we load our browser now we are going to see this:

We are done with the navbar.

Create the product component and follow the same steps we took while creating the navbar component and once you are done, add the following code inside the product.vue component.

<template>
  <div class="md-layout">
    <div class="md-layout-item md-medium-size-33 md-small-size-30 md-xsmall-size-100">
      <md-card>
        <md-card-header>
          <md-card-header-text>
            <div class="md-title">{{ name }}</div>
          </md-card-header-text>
        </md-card-header>
        <md-card-content>
          <md-card-media>
            <img :src="image" height="250" />
          </md-card-media>
          <span>{{ "$" + price }}</span>
        </md-card-content>
        <!-- <md-card-actions> -->
        <md-button class="md-primary" @click="addToCart(id)">Add to Cart</md-button>
        <!-- </md-card-actions> -->
      </md-card>
    </div>
  </div>
</template>

<script>
export default {
  name: "product",
  props: ["id", "name", "image", "price"],
  methods: {
    addToCart(id) {
      this.$store.dispatch("addToCart", id);
    }
  }
};
</script>

<style lang="scss" scoped>
.md-layout-item {
  min-height: 40px;
  margin-top: 4%;
  margin-bottom: 4%;
  width: 100%;
  .md-card {
    width: 320px;
    margin: 4px;
    display: inline-block;
    vertical-align: top;
    .md-card-content {
      span {
        color: red;
        font-weight: bolder;
      }
      .md-card-media {
        img {
          width: 50%;
        }
      }
    }
  }
}
</style>

In the product <template></template>, we started by wrapping our div with a grid layout and a card. In the card-header-text, we outputted the name of our product using data binding {{ name }}, we also bind the {{ "$" + price }} the price to <card-content> and we bind :image to the SCR attribute of our image tag. @click="addToCart(id)” fires the button when clicked and we passed in an id.

In the <script></script>, We use props to hold an array that will share data on each product from the parent component to the child components.

We also add the methods: {} property which holds one method addToCart(id) {}. and the function is to be called at the instance of when a button is clicked.

Once that is done import the product list in the app.vue.

<Product
      v-for="product  in  products"
      :key="product.id"
      :id="product.id"
      :name="product.name"
      :image="product.image"
      :price="product.price"
    />

import Product from "./views/Product.vue";

computed: {
    products() {
      return this.$store.getters.products;
    }
  },

components: {
    Navbar,
    Product
  }

We imported the product component. We display the data in our store.js by the use of v-for directive and we loop through it.

We also registered the product in the components property.

We also created a function in the computed products() which enable us to get access to the data in the store.js.

Reload the page on your browser:

Shopping Cart with Vue

Creating the last component:

We are going to create a component called Shopping.vue and in this component, we are going to display each product a user adds to the cart.

After creating the component, write the code below:

<template>
  <div id="shopping-cart">

   <md-button class="md-accent md-raised" @click="showList()" id="show">{{ cartCount }}</md-button>

   <div id="shoppingList" class="shoppingBody">
     <div class="md-layout" v-for="(item, index) in cart" :key="index">
       <div class="md-layout-item">{{ item.name }}</div>
       <div class="md-layout-item">
         <img :src="item.image" alt />
       </div>
       <div class="md-layout-item">{{ '$' + item.price }}</div>
       <div class="md-layout-item">
         <md-button class="md-primary" @click="removeItem(index)">Remove Cart</md-button>
       </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "Shopping",
  computed: {
    StoreCart() {
      return this.$store.getters.StoreCart;
    },
    cartCount() {
      return this.StoreCart.length;
    },
    cart() {
      return this.$store.getters.StoreCart.map(cartitems => {
        return this.$store.getters.products.find(itemForSale => {
          return cartitems === itemForSale.id;
        });
      });
    }
  },
  methods: {
    removeItem(index) {
      this.$store.dispatch("removeItem", index);
    },
    showList() {
      var modal = document.getElementById("shoppingList");
      var btn = document.getElementById("show");
      btn.onclick = function() {
        modal.style.display = "block";
      };
      window.onclick = function(event) {
        if (event.target == modal) {
          modal.style.display = "none";
        }
      };
    }
  }
};
</script>

<style lang="scss" scoped>
#shopping-cart {
  width: 100%;
  max-height: 400px;
  border: 1px solid rgba(#000, 0.12);
  .md-layout {
    margin-top: 2%;
    width: 70%;
    background-color: rgb(255, 255, 255);
    margin: auto;
    z-index: 9999999;
    padding: 20px;
    border-bottom: 1px solid rgb(126, 126, 126);
    .md-layout-item {
      margin-top: 2%;
      img {
        width: 25%;
      }
    }
  }
  .md-span {
    text-align: right;
    width: 100%;
  }
  .shoppingBody {
    display: none;
    position: fixed;
    z-index: 9999999;
    padding-top: 25px;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    background-color: rgb(0, 0, 0);
    background-color: rgba(0, 0, 0, 0.4);
  }
}
</style>

In the <script></script> tag, we computed a function called storeCart(). inCart function gives us access to the data in store.js.

cartCount() check in the length of data in storeCart() just as show below:

cart() maps through the data.

In the methods property, we called two functions showList() and removeCart(). removeCart() It removes an item from the cart if users change its mind at a particular product.

showList() shows the list of items in the cart just as show below:

Shopping Cart with Vue
Shopping Cart with Vue

Conclusion

It was a great article, and we were able to understand how to use material design, Vuex, and how to create a Vue component.

Until next time, stay safe and keep Coding!


Share on social media

//