Creating a product configurator with Vue #2

2022-11-04 Update

This project was first created back in 2019 to serve as an example how to build a product configurator using Vue 2 and Vuex. It used Vue CLI scaffolding.

We are in 2022 now and times have changed. Project scaffolding is still possible using the Vue CLI, but the Vite CLI is the new kid on the block which is much faster. Also, Vue 3 was released (already somewhere in 2021) and Pinia is the new defacto for state management (formerly it was Vuex).

Enough reasons to update this demo project. Please continue reading if you are here for the ‘old’ version. I will write about the updated version in a blog coming soon.

Part 2: The Vuex store

In this post I’ll describe the setup of the Vuex store for the product configurator that was introduced in part 1. The product configurator is part of a fictive webshop where customers may configure and order personal postcards.

Since usability becomes more and more important these days, this blog series covers a product configurator from concept to implementation.

Vuex

I’ll use Vuex (with modules) to handle state. Although a product configurator seems to be a relatively small part of a webshop, using Vuex will result in a better maintainable codebase when the app grows and becomes more complex!

Moreover, Vuex is rather opinionated about how you should implement certain features which always gives me a nice handhold when implementing this kind of features.

The code for this post can be found on Github, it’s release v0.1.

A quick note on the code samples: After creating this release and writing this post, I continued with the actual implementation of the product configurator, which will be described in the next post. I slightly changed the state of the application to get it all working. I have not changed the code in this release accordingly, so code samples in this post may be a bit outdated. Nevertheless, they do serve the point to explain the general Vuex setup.

If you follow along, simply fork the Github repository and run npm install and npm serve.

Below is the sketch of the product configurator we’re building (the concept is described in detail in the previous post).

The following actions may take place during the configuration of the postcards:

  • add a postcard
  • remove a postcard
  • update the total price
  • reset a configuration for a given postcard
  • add to cart and proceed to the checkout

These will become the actions for the Vuex store. I’ll discuss the setup of this part of the store in a minute.

Vuex modules

First a word on Vuex modules. For a small project like this it might not be necessary, but your future self will be thankful if the project grows 😉

Moreover, setting up the modules is not very hard. But what modules do we have in this project?

Clearly there is a configurator module consisting of all aspects related to postcards. Let’s imagine we also have accounts in the webshop. An account, with login, logout and so on is a good candidate for another module. In addition, the cart could be a module. However, the latter is out of scope for the current post, so let’s assume we only need modules for the configurator and for  accounts. The actions for the configurator are described above, for the account module I come to the following set of actions:

  • toggle Login form
  • attempt login
  • logout

Vuex modules implemented

Implementing the store with modules is quite easy. However, instead of the store.js file that comes with Vuex by default, we need a /store folder holding an index.js file and a modules folder that holds ‘account.js’ en ‘configurator.js’. Each module consists of its own state, actions, mutations, getters and (possibly) submodules if required by the project. The store/index.js file looks like this:

The store itself is imported in main.js. This happens by default when adding Vuex to the project during setup with @vue/cli.

Configurator module

The state of the configurator module contains a products array and a price. We initialize the price to € 1.50. A single product is initialized in the products array. It’s an object with a unique id and a config object holding all the properties a postcard may have:

Note that the id field is generated using the uuidv4 function. This is a truly unique string and we need it as a key later on. Otherwise the remove product feature won’t work as expected!

Our actions are defined as follows:

The current application has no backend, so everything is synchronous and actions are not required. Hence, we could have used mutations directly. However, adding actions makes it possible to add asynchronous behavior in the future, for example to let a dedicated API calculate the price of a product.

The mutations are defined below:

The addProduct mutation simply pushes a new product object onto the products array. The removeProduct mutation on the other hand removes the product with a certain index. Add to cart functionality is outside the scope of this project, we could think of clearing the products array and reset the price. The updatePrice mutation computes the price per product and sums all individual product prices using Javascript’s native reduce method. The productPrice function is a very simple algorithm:

Finally, the resetProduct mutation uses the splice method to remove the product at the desired index and adds a new product.

Account module

The account module is much simpler with a state holding just two booleans. These describe the logged in state and the show login form state. The actions and mutations are rather self explanatory so I’ll leave it to you.

Testing the store

Without a complete frontend with Vue components to connect to the store yet, it is already possible to test the store functionality. We can use the developer tools for this! The store is available on all components and (in Chrome) we can select the <Root /> or <App /> component and refer to it by $vm0.

With the dispatch function available on the store we can test all actions. For example, adding a product is done by executing

$vm0.$store.dispatch(‘configurator/addProduct’)

Note that we need to add the name of the module followed by a forward slash to let the store know it is the actions in module ‘configurator’.

Mutations are also possible using commit:

$vm0.$store.commit(‘configurator/addProductMut’)

However, a real playground is much nicer compared to the dev tools 😉

Connecting a component to the store

I created a simple implementation in App.vue to show you how to connect the store to a component. I’ll assume some experience with Vuex as I am using mapState and mapActions. These two functions simply make state variables and actions available in a component. However, with modules, we need to make sure we pass the module name as the first argument.

Adding

...mapState('configurator', {
     products: 'products'
})

to the computed section, enables us to use the products array in the template (in a v-for loop for example).

Likewise,

...mapActions('configurator', ['addProduct'])

enables us to use ‘addProduct’ as a normal method and attach it to the add product button.

Conclusion and next steps

In this post I have described the setup of the store including modules. The store functions could be tested with the dev tools of a browser, but a real component you can click on is much more fun!

In the upcoming post I’ll start with the actual implementation of the postcard configurator. The interesting part is mainly how we create the product component and build it up from smaller components using v-model on custom components.

Stay tuned!



Mijn Twitter profiel Mijn Facebook profiel
Pim Hooghiemstra Webdeveloper and founder of PLint-sites. Loves to build complex webapplications using Vue and Laravel! All posts
View all posts by Pim Hooghiemstra

Leave a Reply

Your email address will not be published. Required fields are marked *