Categories
Vue 3 Projects

Create a Shopping Cart with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a shopping cart app with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create shopping-cart

and select all the default options to create the project.

We also need the Vue Router package to let us navigate to different pages in the app.

To do this, we run:

npm i vue-router@next

Create the Shopping Cart

The first step for creating the shopping cart is to create the view files.

We create the views folder in the src folder.

Then inside it, we add the Cart.vue and Store.vue files to create the store page which we can browser.

Cart.vue has the cart page.

Then in main.js , we add the Vue Router into our app by writing:

main.js

import { createApp } from "vue";
import App from "./App.vue";
import Cart from "./views/Cart";
import Store from "./views/Store";
import { createRouter, createWebHashHistory } from "vue-router";

const routes = [
  { path: "/", component: Store },
  { path: "/cart", component: Cart }
];

const router = createRouter({
  history: createWebHashHistory(),
  routes
});

const app = createApp(App);
app.use(router);
app.mount("#app");

We import the view component files we created earlier.

Then we add them to the routes array.

Next, we call createRouter to create the router object.

We add the routes object, we created earlier inside the argument object.

createWebHashHistory makes Vue Router add a # sign between the first segment and the other segments of the URL.

And then we call app.use with router to add the router.

To create a simple store page, we go into Store.vue and write:

<template>
  <div>
    <h1>Store</h1>
    <div v-for="item of items" :key="item.id">
      <p>{{ item.name }}</p>
      <img :src="item.imageUrl" />
      <button @click="removeFromCart(item.id)" v-if="isInCart(item.id)">
        remove from cart
      </button>
      <button @click="addToCart(item.id)" v-else>add to cart</button>
    </div>
    <button @click="$router.push('/cart')">check out</button>
  </div>
</template>

<script>
const items = Object.freeze([
  {
    id: 1,
    imageUrl: "grape.jpg",
    name: "grape",
  },
  {
    id: 2,
    imageUrl: "orange.jpg",
    name: "orange",
  },
  {
    id: 3,
    imageUrl: "apple.jpg",
    name: "apple",
  },
]);

export default {
  name: "Store",
  data() {
    return {
      items,
      cart: [],
    };
  },
  methods: {
    isInCart(itemId) {
      if (!localStorage.getItem("cart")) {
        localStorage.setItem("cart", JSON.stringify([]));
      }
      const cartItem = this.cart.find(({ id }) => id === itemId);
      return Boolean(cartItem);
    },
    addToCart(itemId) {
      const item = this.items.find(({ id }) => id === itemId);
      if (!localStorage.getItem("cart")) {
        localStorage.setItem("cart", JSON.stringify([]));
      }
      const cartItems = JSON.parse(localStorage.getItem("cart"));
      cartItems.push(item);
      localStorage.setItem("cart", JSON.stringify(cartItems));
      this.cart = JSON.parse(localStorage.getItem("cart"));
    },
    removeFromCart(itemId) {
      const cartItems = JSON.parse(localStorage.getItem("cart"));
      const index = cartItems.findIndex(({ id }) => id === itemId);
      cartItems.splice(index, 1);
      localStorage.setItem("cart", JSON.stringify(cartItems));
      this.cart = JSON.parse(localStorage.getItem("cart"));
    },
  },
};
</script>

We render the store items with v-for .

We display the remove from cart button if the item is already added top the cart.

And we show the add to cart button otherwise.

The check is done by the isInCart method, which gets the cart items from the this.cart reactive property and check if find returns anything given the itemId .

addToCart adds the item to the cart entry in local storage, which is an array that we create if it doesn’t exist.

After that, we update the this.cart reactive property with the latest value from local storage.

removeFromCart finds the index from the cart items from local storage by the itemId with findIndex .

Then we call splice to remove the item by the index .

And then we call setItem to update the cart with the latest items in the cart.

And we update this.cart with the latest values form local storage.

items have the store items.

The checkout button calls $router.push with '/cart' to go the cart page.

To add the content for the cart page, we write the following in Cart.vue:

Cart.vue

<template>
  <div>
    <h1>Cart</h1>
    <div v-for="(c, index) of cart" :key="c.id">
      <p>{{ c.name }}</p>
      <img :src="c.imageUrl" />
      <button @click="removeFromCart(index)">remove from cart</button>
    </div>
  </div>
</template>

<script>
export default {
  name: "Cart",
  data() {
    return {
      cart: [],
    };
  },
  methods: {
    removeFromCart(itemId) {
      const cartItems = JSON.parse(localStorage.getItem("cart"));
      const index = cartItems.findIndex(({ id }) => id === itemId);
      cartItems.splice(index, 1);
      localStorage.setItem("cart", JSON.stringify(cartItems));
      this.cart = JSON.parse(localStorage.getItem("cart"));
    },
    getCart() {
      if (!localStorage.getItem("cart")) {
        localStorage.setItem("cart", JSON.stringify([]));
      }
      this.cart = JSON.parse(localStorage.getItem("cart"));
    },
  },
  beforeMount() {
    this.getCart();
  },
};
</script>

We have the same remvoeFromCart method as in Store.vue .

getCart gets the cart item from local storage and then set the returned value as the value of the this.cart reactive property.

And then we render the this.cart entries with v-for in the template.

We have the remove from cart button to remove the item with removeFromCart .

Finally, in App.vue , we write:

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

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

<style>
img {
  width: 200px;
  height: 200px;
}
</style>

to add the router-view so we can see the route that Vue Router renders.

We also shrink the images to 200px by 200px with the style tag.

Conclusion

We can create a simple shopping cart easily with Vue 3 and JavaScript.

Categories
Vue 3 Projects

Create a To-Do List with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a to-do list app with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create todo-list

and select all the default options to create the project.

We also need the uuid package to let us generate unique IDs for our to-do items.

To do this, we run:

npm i uuid

Create the To-Do List

To create the to-do list, we write:

<template>
  <div>
    <form @submit.prevent="add">
      <input v-model="todo" />
      <button type="submit">Add</button>
    </form>

    <div v-for="(todo, index) of todos" :key="todo.id">
      {{ todo.todo }}
      <button @click="deleteTodo(index)">delete</button>
    </div>
  </div>
</template>

<script>
import { v4 as uuidv4 } from "uuid";

export default {
  name: "App",
  data() {
    return {
      todo: "",
      todos: [],
    };
  },
  methods: {
    add() {
      const { todo } = this;
      this.todos.push({
        id: uuidv4(),
        todo,
      });
      this.todo = "";
    },
    deleteTodo(index) {
      this.todos.splice(index, 1);
    },
  },
};
</script>

We have the form with the @submit directive to let us submit the form.

The prevent modifier lets us submit our form on the client-side instead of the server-side.

Then we add v-for to render the to-do items.

The key prop is set to the id property, which is the unique ID for a to-do item.

We also have a button in each row to delete an item at the given index with the deleteTodo method.

In the component object, we have the todo reactyive property, which is bound to the input with v-model .

todos has an array of to-do items.

The add method calls the push method to append an item to the this.todos array.

We call the uuidv4 function to return a unique ID we use for the to-do item.

Then we make the this.todo reactive property an empty string to clear the input.

In the deleteTodo method, we call splice with the index and 1 to delete the to-do item at the given index.

Conclusion

We can create a to-do list easily with Vue 3 and JavaScript.

Categories
Vue 3 Projects

Create a Simple Calculator with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a simple calculator with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create calculator

and select all the default options to create the project.

We also need the Math.js package to let us evaluate math expression strings.

To install it, we run:

npm install mathjs

Create the Calculator

We can create the calculator by writing:

<template>
  <div>
    <div>{{ expression }}</div>
    <form @submit.prevent="calculate">
      <div>
        <button type="button" @click.stop="expression += '+'">+</button>
        <button type="button" @click.stop="expression += '-'">-</button>
        <button type="button" @click.stop="expression += '*'">*</button>
        <button type="button" @click.stop="expression += '/'">/</button>
      </div>
      <div>
        <button type="button" @click.stop="expression += '.'">.</button>
        <button type="button" @click.stop="expression += '9'">9</button>
        <button type="button" @click.stop="expression += '8'">8</button>
        <button type="button" @click.stop="expression += '7'">7</button>
      </div>
      <div>
        <button type="button" @click.stop="expression += '6'">6</button>
        <button type="button" @click.stop="expression += '5'">5</button>
        <button type="button" @click.stop="expression += '4'">4</button>
        <button type="button" @click.stop="expression += '3'">3</button>
      </div>
      <div>
        <button type="button" @click.stop="expression += '2'">2</button>
        <button type="button" @click.stop="expression += '1'">1</button>
        <button type="button" @click.stop="expression += '0'">0</button>
        <button type="submit">=</button>
      </div>
      <div>
        <button type="button" @click.stop="expression = ''">Clear</button>
      </div>
    </form>
  </div>
</template>

<script>
import { evaluate } from "mathjs";

export default {
  name: "App",
  data() {
    return {
      expression: "",
    };
  },
  methods: {
    calculate() {
      this.expression = evaluate(this.expression);
    },
  },
};
</script>

<style scoped>
button {
  width: 20px;
}

#clear-button {
  width: 50px;
}
</style>

First, we add the expression string to the top of the template.

Then, we add the buttons for the calculator.

They are used for letting us append characters to the expression we are evaluating.

We do this by concatenating characters to the expression reactive property.

All except one button is set to type button so that we won’t run the calculate method until the = button is clicked.

Also, we have the stop provider to stop the propagation of the click event.

In the component object, we have the calculate method to evaluate the expression we entered.

We have the @submit.prevent directive to let us call calculate when we submit the form when we click =.

prevent lets us prevent the default server-side submission mechanism.

We call the evaluate method from mathjs to evaluate the expression we entered.

Then we set the this.expression reactive property to the returned result.

In the style tag, we set the button width to 20px, and we set the clear button to 40px so that the text will be inside the button.

Conclusion

We can add a simple calculator easily with Vue 3 and JavaScript.

Categories
Vue 3 Projects

Create a Tip Calculator with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a tip calculator with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create tip-calculator

and select all the default options to create the project.

Create the Tip Calculator

To create the tip calculator, we write:

<template>
  <div>
    <form @submit.prevent="calculate">
      <fieldset>
        <label>subtotal</label>
        <input v-model.number="tip.subtotal" />
      </fieldset>

      <fieldset>
        <label>number of people sharing the bill</label>
        <input v-model.number="tip.numDiners" />
      </fieldset>

      <fieldset>
        <label>tip percentage</label>
        <select v-model.number="tip.tipPercentage">
          <option value="0">0%</option>
          <option value="0.05">5%</option>
          <option value="0.1">10%</option>
          <option value="0.15">15%</option>
          <option value="0.2">20%</option>
        </select>
      </fieldset>

      <button type="submit">Calculate</button>
    </form>

    <div v-if="result.total">
      <p>total: {{ result.total }}</p>
      <p>total per diner: {{ result.totalPerDiner }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      tip: {
        subtotal: 0,
        numDiners: 0,
        tipPercentage: 0,
      },
      result: {},
    };
  },
  computed: {
    subtotalValid() {
      return +this.tip.subtotal >= 0;
    },
    numDinersValid() {
      return +this.tip.numDiners > 0;
    },
    tipPercentageValid() {
      return +this.tip.tipPercentage >= 0;
    },
  },
  methods: {
    calculate() {
      const { subtotalValid, numDinersValid, tipPercentageValid } = this;
      if (!subtotalValid || !numDinersValid || !tipPercentageValid) {
        return;
      }
      const { subtotal, numDiners, tipPercentage } = this.tip;
      const total = subtotal * (1 + tipPercentage);
      this.result = { total, totalPerDiner: total / numDiners };
    },
  },
};
</script>

The first input binds to the tip.subtotal reactive property, which has the subtotal before the tips.

v-model lets us binds the inputted value to the reactive property.

The number modifier lets us convert the inputted value to the number automatically.

Similarly, we have the ‘number of people sharing the bill’ field to enter the number of people that split the bill.

The 3rd field has the tip.tipPercentage property with the tip percentage.

To let users submit the form, we add a button with the type attribute set to submit to submit the form.

We have the @submit directive to let us run the calculate method to let us do the calculation.

The prevent modifier lets us prevent the default submit behavior, which lets us do client-side submissions instead of server-side.

The div below the form has the results.

We only display it if result.total is calculated.

In the component object, we have the data method that has the initial value of the tip reactive property.

result has the result object.

The calculate method lets us get all the values from the form and calculate the value.

First, we check for the validity of the values with the computed properties.

subtotalValid compares the subtotal to make sure it’s bigger than or equal to 0.

We do similar comparisons with the other 2 computed properties.

We calculate the total and the result.

This result is displayed in template.

Conclusion

We can create a tip calculator easily with Vue 3.

Categories
Vue 3 Projects

Create an Image Modal with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create an image modal with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create image-modal

and select all the default options to create the project.

Create the Image Modal

To create the image modal, we write:

<template>
  <div>
    <button @click.stop="displayModal = true">open modal</button>
    <div id="modal" v-if="displayModal">
      <button @click="displayModal = false">x</button>
      <div>
        <button @click="prev">&lt;</button>
        <img :src="image" />
        <button @click="next">&gt;</button>
      </div>
    </div>
  </div>
</template>
<script>
const images = [
  "https://images.dog.ceo/breeds/pomeranian/n02112018_5091.jpg",
  "https://images.dog.ceo/breeds/mountain-swiss/n02107574_753.jpg",
  "https://images.dog.ceo/breeds/leonberg/n02111129_3028.jpg",
];
export default {
  name: "App",
  data() {
    return { index: 0, image: images[0], displayModal: false };
  },
  methods: {
    next() {
      this.index = (this.index + 1) % images.length;
      this.image = images[this.index];
    },
    prev() {
      this.index = (this.index - 1) % images.length;
      this.image = images[this.index];
    },
    onClickOutsode(e) {
      if (e.target.localName !== "button") {
        this.displayModal = false;
      }
    },
  },
  mounted() {
    window.addEventListener("click", this.onClickOutsode);
  },
};
</script>

<style scoped>
img {
  width: 200px;
  height: 200px;
}

#modal {
  position: absolute;
  top: 20px;
  left: 20px;
  border: 1px solid gray;
  background-color: white;
}
</style>

The open modal button sets displayModal to true to let us open the modal.

We add the stop modifier so that the click event doesn’t bubble up to the ancestor elements so that it doesn’t trigger click events on them.

The div with ID modal has the v-if set to displayModal to let us show it only when displayModal is true .

Inside it, we have the x button to set displayModal to false to close the modal.

Then we have 2 more buttons to move to the previous and next images respectively.

img has src set to image to display the current image.

In the component object, we have the next method which gets the index of the next image by adding 1 to this.index and get the remainder of that when divided by images.length .

Similarly, we have the prev method, which gets the previous image by subtracting 1 from this.index to get the index of tjhe previous image.

The onClickOutside method is used by the window ‘s click listener to detect clicks from everything inside the browser screen.

We check that localName isn’t 'button' .

If it isn’t, then we set this.displayModal to false to close the modal.

This makes sure that all the buttons except the ‘x’ button in our code don’t close the modal, but when we click outside the modal closes.

Then in the mounted hook, we add the click listener with addEventListener to listen for clicks.

The mounted hook is run when all the elements are loaded, so this is the appropriate hook to add the click listener.

Then in the style tag, we make the div with ID modal a modal by setting position to absolute to make it site above the open modal button.

And then we change the position of it with the top and left properties.

border adds a border to the modal div so we can see the modal.

background-color is set to white so that it doesn’t have a transparent background.

Conclusion

We can create our own modal easily in our app with Vue 3.