Create your Blockchain DApp with Ethereum and VueJS – Tutorial Part 2

In the second part of the tutorial we are going to develop the front-end and see how to interact with the smart contract developed in the PART 1.

If you missed the introduction and you want to know what this tutorial is about, please read the intro.

In this part we are going through the following topics:



Set up of the Vue project and Web3.js installation

For the set up we are going to use Vue command line interface (Vue CLI): if you have not installed it yet here you can find the commands

$ npm install -g @vue/cli
$ npm install -g @vue/cli-init

Then type the following command to check if everything was installed correctly:

$ vue ––version

Now let’s create a new project with the following command (you can create the project in any folder you want):

$ vue init webpack app-users

This command will start a wizard, which will ask you for general information like the app name, contact and description (just press enter).

On the question Install vue-router type Y for yes; type N for the questions:

  • Use ESLint to lint your code?
  • Set up unit tests
  • Setup e2e tests with Nightwatch?

? Project name apptest
? Project description A Vue.js project
? Author
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

Once the installation is done, go inside the folder of the project which has just been created:

$ cd app-users

And let’s pull into the project the latest stable release of Web3.js (at the time of this writing):

$ npm install --save web3@0.20.6

Note that if you do not specify the version, npm will install the latest version of Web3.js (still in beta) and the dApp will not work.

Finally let’s run the development server typing the following command in the project folder:

$ npm run dev

On the terminal you should see something like this:

Ethereum VueJS Dapp - Terminal NPM RUN DEV

Project set up and structure

Open the file index.html in the root folder app-users and paste the following CSS in the head section:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href=”/css/app.css">

The body has to include only the following tag:

<div id="app"></div>

The file index.html should look like this:
https://github.com/danielefavi/ethereum-vuejs-dapp/blob/master/app-users/index.html

The folder app-users/src contains the source of our project and now we are going to tweak it a little: delete the folder routes and create two folders called libs and views and finally create an empty file called routes.js.

In the PART 1 of the tutorial you deployed the smart contract Users.sol in the blockchain: now copy the file build/contracts/Users.json into the folder app-users/src/assets/.

The structure of the folder src should be like this:

  • assets: contains the JSON configuration files like the compiled smart contract.
  • components: Vue components folder.
  • libs: contains classes and extra functionalities.
  • views: pages components.
  • App.vue: master page component.
  • main.js: Vue bootstrap file.
  • routes.js: URL / page view mapping.


The BcExplorer class: Web3.js made easy

Our dApp uses the class BcExplorer to handle the interactions with the blockchain; BcExplorer makes easy the use of Web3j.js.
With BcExplorer you can:

  • Handle the connection.
  • Initialize the multiple smart contracts.
  • Call easily the functions from different smart contracts.

The class BcExplorer is located in the app-users/src/libs folder.

Note: the BcExplorer class works with the stable version of Web3.js 0.X but it does not work with the latest beta 1.x.

Let’s start with the project!

The file main.js is the bootstrap file of our dApp: the only line of code added here is:

window.Event = new Vue();

It will help to handle the cross-components events.
As you can see from the main.js, the first component that will be rendered is App.vue.

The main page app: App.vue

App.vue defines the structure of the pages with the menu on the top (TopMenu component) followed by the page content <router-view>.

The content page will be displayed only when the connection with the blockchain is established successfully (bcConnected is true) and no error occurred (bcConnectionError is false).

<div class="main-content" v-show="bcConnected && !bcConnectionError">
    <router-view></router-view>
</div>

NOTE: you can be successfully connected to the blockchain but the address of the smart contract might be wrong; bcConnectionError is a variable which indicates if general errors occurred with the blockchain.

Where are bcConnected and bcConnectionError defined? Where are the functions that handle the connection with the blockchain?
If you check the script section of App.vue you will see that the mixin (click here to read mixin on Vue.js official documentation) mixinViews.js is included: bcConnected and bcConnectionError are declared here.

The mixin mixinViews.js

In the mixin libs/mixinViews.js are handled the set up of Web3.js and the initialization of the smart contracts; so all the components that use this mixin will initialize Web3.js and the smart contracts (if not initialized yet).

In the mixin you can see the declaration of the function created(): when a component includes this mixin, the code within the created() method in the mixin is mixed with the created() method of the component.

The function created() calls the method init(). Following you can see the code of the method init() in the mixin:

init() {
    // when this file is imported to other component it checks if the BcExplorer
    // is instatiated.
    if (window.bc == undefined) {
        window.bc = new BcExplorer;

        // connecting to the blockchain and intializing the Users smart contract
        window.bc.initWithContractJson(UsersContract, 'http://127.0.0.1:7545’)
        .then((error) => {
            // handling the connection error
            if (error) {
                this.bcConnected = false;
                this.showConnectionErrorMessage(error);
            } else {
                // calling a smart contract function in order to check the contract address
                // is correct. NOTE: here you might be connected successfully.
                this.isRegistered()
                .then(res => {
                    this.bcConnectionError = false;
                    this.bcConnected = this.blockchainIsConnected();
                })
                .catch(error => {
                    this.showConnectionErrorMessage(error);
                    this.bcSmartContractAddressError = true;
                });
            }
        })
        .catch(error => this.showConnectionErrorMessage(error));
    } // end if
},

The class BcExplorer is instantiated in window.bc so it can be accessed everywhere.

In case you are wondering why the initialization of BcExplorer and Web3.js is in a mixin and not in the main.js.
I will give an example: you have a dApp with 10 pages and only in 2 of them you are using Web3.js; since you need Web3.js in 2 pages only, you can initialize Web3.js in one of those two pages instead of doing it everywhere in the main.js, which also slows down the initial loading.

The TopMenu component

This component shows the top menu. You can find this component in src/components/TopMenu.vue.
The top menu shows:

  • The link to the page of the status list.
  • The link to the register page if the user is not registered yet or the link to the profile page if the user is registered.
  • Message if the user is connected to the blockchain.
Ethereum VueJS dApp - top menu

If you check the code of this component you will see it includes the mixin mixinViews. We need the BcExplorer functionalities because we have to check if the visitor is already registered and to show if the connection with the blockchain is established.

To show the message that the connection is established we can easily use the variable bcConnected defined in the mixin:

<strong :class="connectedClass">
    {{ bcConnected ? 'Connected' : 'Not Connected' }}
</strong>

In the created method you can see that

Event.$on('userregistered', this.checkUntilUserIsRegistered);

this line of the code triggers the function checkUntilUserIsRegistered when the event userregistered is fired. The function checkUntilUserIsRegistered checks if the user is registered and it changes the link Register to Profile accordingly.

After the event userregistered is fired the function checkUntilUserIsRegistered checks every second if the user has been registered successfully calling function isRegistered (declarated in the mixinView.js):

isRegistered() {
    return new Promise((resolve, reject) => {
        window.bc.getMainAccount()
        .then(account => {
            window.bc.contract().isRegistered({ from: account }, (error, res) => {
                if (error) reject(error);

                resolve(res);
            });
        })
        .catch(error => reject(error));
    });
},

The function isRegistered() first gets the user’s account address calling the method getMainAccount(). That function returns the account address (don’t get confused with the coinbase address) through a promise. Once the promise from getMainAccount() is received the smart contract function isRegistered is called passing to it the account address as a parameter { from: account }.

The checking stops when the block is mined and so the user is actually registered.

This control must be done every second (and not only once) because the mining of the block needs time.
Let me explain it with an example: let’s suppose that your dApp uses a blockchain where the block mining is 5 minutes long; when a user signs up a transaction is submitted but it can take 5 minutes before the block is mined (so the user will be effectively registered).
If you are using Ganache the mining is instantaneous.

Another function in the created() method is called: checkUserIsRegistered.
This function changes the link from Register to Profile as well if the user is registered but the control is performed when the component is created.
This function has a timer too, that performs the check every half of a second, as connection to the blockchain can require some time; the checking stops when a response is received.

The view components

Let’s check the main functions used in the views.

How to get the users list on List.vue

Ethereum VueJS dApp - List

In the file List.vue you can see all the status of the registered user. Below you can see the function that retrieves all the registered users:

getAllUsers(callback) {
    // getting the total number of users stored in the blockchain
    // calling the method totalUsers from the smart contract
    window.bc.contract().totalUsers((err, total) => {
        var tot = 0;
        if (total) tot = total.toNumber();

        if (tot > 0) {
            // getting the user one by one
            for (var i=1; i<=tot; i++) {
                window.bc.contract().getUserById.call(i, (error, userProfile) => {
                    callback(userProfile);
                });
            } // end for
        } // end if
    }); // end totalUsers call
}

This method first calls the smart contract function totalUsers to get the total number of users; then it gets all the users one by one calling the smart contract function getUserById starting with the user with ID 1 to the user with the ID returned by totalUsers function.

How to register a user profile

Ethereum VueJS dApp - Register page

When the user is on the registration page (file Register.vue) and he presses the Register button the function performSubmit() is triggered. performSubmit() calls the function performUserRegistration() that performs the actual user registration:

performUserRegistration(address) {
    window.bc.contract().registerUser(
        this.userName,
        this.userStatus,
        {
            from: address,
            gas: 800000
        },
        (err, txHash) => {
            this.submitting = false;

            if (err) {
                this.showErrorMessage(err);
            }
            else {
                this.successMessage = true;

                // it emits a global event in order to update the top menu bar
                Event.$emit('userregistered’, txHash);

                // the transaction was submitted and the user will be redirected to the
                // profile page once the block will be mined
                this.redirectWhenBlockMined();
            }
        }
    )
},

As you can see, the smart contract function registerUser to register a user is called. The function must receive 3 parameters:

  • The name of the user.
  • The status the user.
  • An object with two attributes:
    • from: the account address of the sender.
    • gas: amount of gas you are willing to pay for this transaction.

If the registration is successful a global event userregistered will be fired:

Event.$emit('userregistered', txHash);

This event will be caught by the TopMenu component as described before.
Then redirectWhenBlockMined() is triggered: this method waits until the block is mined then it redirects the user to its own profile page_

Related Articles

Create your Blockchain DApp with Ethereum and VueJS - Tutorial Part 1

Category: Blockchain

In this first part of the tutorial we are going to create the smart contract that handles the registration of users; then we are going to deploy the smart contract to the blockchain using ...

Create your Blockchain DApp with Ethereum and VueJS - Tutorial Intro

Category: Blockchain

This is a simple decentralized application built using Ethereum blockchain and VueJS for the front-end. This DApp example lets the users store their name and status on the ...

How to Test Smart Contracts - Tutorial

Category: Blockchain

Testing a smart contract is a must of the blockchain development process. Remember that the blockchain does not forgive you any errors because of its immutability! The only way to fix a bug ...

What is a fork? Why is it dangerous?

Category: Blockchain

Often a blockchain can have some flaws, bugs or it just needs improvements. To fix those vulnerabilities the blockchain has to be forked. A fork rewrites the rules which a full node must follow in ...

Ethereum Smart Contracts GUI Generator

Category: Blockchain

If you need to create a graphical user interface to interact with your Ethereum smart contracts, then you might be interested in the ethereum-interface-generator NPM package. The NPM package ...

Blockchain For Not Technical People (public speech)

Category: Blockchain

A 4 minutes speech about blockchain I delivered during a course on public speaking in November 2019.