Simple Full-stack Blockchain Test Network with Angular, NodeJs – EP2: Front-end Architecture with Angular

In the EP1, we talked about back-end. Now, I would like to purely write about front-end. The fundamental concept about Angular Framework, how I architect this Angular project, as well as interesting and more advanced topic about Angular will be expanded.

For those who want to explore my source code, the link is at Github repo. However, I note that the source code is for educational purpose only, NOT in production.

In the previous block Ep1, I have written about back-end code, and it is separated into 3 parts, which are:

  1. wallet
  2. faucet
  3. explorer

Again, I created more separate folders in /src for the Angular project, which are wallet/, faucet/ and explorer/ as below:

This image has an empty alt attribute; its file name is Screen-Shot-2019-05-03-at-23.12.28.png

Also, I defined them as Lazy loading feature module at app.module.ts.

Lazy loading is a design pattern used to defer initialisation of an object until the point at which it is needed.

This image has an empty alt attribute; its file name is lazyloading.png
app/app.module.ts

The main purpose of doing this is to help developers to easily separate different features (including routing). Moreover, It is one type of web optimisation, since users are not required to load all code in the first time and only necessary code will be loaded when users only want one.

Component architecture: Crash Concept

Angular is component-based framework, which mainly supported typescript (super version of javascript language) . Its main idea is to separate and encapsulate web page into several part, called web component . This is because it can be reusable, easily readable, and maintainable.

Alternatively, some developers may prefer React.js or Vue.js .

In best practices, if there is component, which is reused and shared across modules, it should be refactored and put into shared module like below:

This image has an empty alt attribute; its file name is shared.png

Generally, there are two types of components, which are:

  1. Stateful Component, Smart Component or Container Component
  2. Stateless Component, Dump Component or Presentational Component

Stateful component is about managing data or interaction with service, then passing the data to Stateless Component.

Stateless Component  is for visualising passed data and emitting event to Stateful component.

Service should encapsulate all business logics of application. As a result, view (component) and business logic are separated, leading to modularity.

This image has an empty alt attribute; its file name is angular-architecture-1024x483.png
Angular Architecture
credit: http://training.fabiobiondi.io/2017/07/10/create-an-accordion-component-in-angular-parent-children-communication/

It is noticeable that the connection between Stateful and Stateless components are back and forth, or “two-way data-binding”

Ok, let see the real example in my project.

Wallet Module

The module includes following section, which composes of corresponding files and folders:

  • components includes all Stateless Components.
  • containers includes all Container Components .
  • guards includes all guard files ,which determine access control to the routes.
  • models includes all model files , which define type of the data for few bugs.
  • services includes all service files.
This image has an empty alt attribute; its file name is wallet-structure.png

It is clear that there, in our case, are two containers, which are <wallet> and <wallet-dashboard>.

<wallet> container

It composes of three components, which are:

This image has an empty alt attribute; its file name is wallet-1024x578.png
  • <wallet-existing> navigates to wallet dashboard container with existing private key that current wallet holds.
  • <wallet-recover> can recover wallet with a private key.
  • <wallet-create> can newly create random private key and use a wallet.
This image has an empty alt attribute; its file name is wallet-html.png
containers/wallet/wallet.component.html

Syntax [] means passing data down from container to dump component .

Syntax () means event up from dump component to container .

In our case:

<wallet-existing
[wallet]="wallet" (use)="onUse($event)">

This can be demonstrated with below diagram.

This image has an empty alt attribute; its file name is wallet-diagram-1.png

The pros of this structure is that when developers want to look about business logic, they just figure it out at only container, not ALL components.

This image has an empty alt attribute; its file name is wallet-ts.png
wallet.component.ts

Container interacts service class with dependency injection pattern. It determined service as private parameter in constructor function ofง component class. Decorator @Injectable() need to be added to service class as below.

This image has an empty alt attribute; its file name is wallet-service.png
wallet.service.ts

It can be seen that all of these services (including ones for wallet dashboard container) can communicate with RESTful API in backend part via HttpClient module(built-in one from Angular). For instance:

This image has an empty alt attribute; its file name is recover-create.png
wallet.service.ts

<wallet-dashboard> container

This image has an empty alt attribute; its file name is wallet-dashboard.png

Similarly, it composes of several stateless components. They are:

  • <wallet-send> Users can send their money.
  • <wallet-receive> Users could copy their own public key to recieve the money.
  • <wallet-key> Users could see their own private key .
  • <wallet-mine> Users can make their own wallet as miner and could explore Transaction Pool or unspent transaction output at that time as below picture:
This image has an empty alt attribute; its file name is UTXO.png

As I want to add real-time feature for both balance and transaction pool , I create class socket service to listen data emitted from backend as following.

This image has an empty alt attribute; its file name is socket-service.png
socket.service.ts

The libraries used are ‘socket.io-client’ and ‘socket.io’ for front-end and backend respectively.

This image has an empty alt attribute; its file name is socket-backend.png
backend/index.js

Faucet Module

This image has an empty alt attribute; its file name is faucet-app.png

Previously, we talk so much about smart components. So let see dump component instead.

<faucet-form> component

Because the web app needs validation in order to prevent sending wrong data to the server.

This image has an empty alt attribute; its file name is faucet-form.png
faucet-form.component.ts

It is seen that the FormBuilder is used via dependency injection, and these following built-in validators are used.

 form = this.fb.group({
    recipient: [
      '',
      Validators.compose([
        Validators.required,
        Validators.minLength(130),
        Validators.maxLength(130)
      ])]
  });

This means that the public key must be needed and be 130-characters string.

This image has an empty alt attribute; its file name is html-faucet.png
faucet-form.component.html

In terms of animation, scss is used instead of css as:

This image has an empty alt attribute; its file name is scss-faucet.png
faucet-form.component.scss

Further Improvement: Request Limit

such as 1 request per 1 public key per 1 hour + captcha

But I have limited time, so I have not implement yet.

Explorer Module

This image has an empty alt attribute; its file name is explorer-file.png

Apart from components, containers, model , and services described before, I should mention about pipes.

This image has an empty alt attribute; its file name is pipe.png

The main purpose of pipe is to take in data as input and transforms it to a desired output. As a result, it is more suitable for users when interaction with users.

The Application of Customised Pipe when filtering data with search box

Users can filter all transactions by putting addresses (or pubic key). Then, users will get transactions, which are only relevant to those addresses including either sender or recipient.

This image has an empty alt attribute; its file name is filter-transaction.png

I used:

[(ngModel)] = "searchText"

This syntax is for 2-way data binding, which are:

  1. Binding model to view
  2. Binding view to model

Now, something updates inside the class. This will reflect our view (model to view), and whenever the user changes the input, the model will be updated (view to model).

This image has an empty alt attribute; its file name is two-way-data-binding-1024x756.png
transaction.component.heml

We need to write filtertransaction Pipe with searchText as parameter as below.

This image has an empty alt attribute; its file name is pipe-transaction.png
filter-transaction.pipe.ts

Then, we have to declare the pipe in explorer.module.ts.

This image has an empty alt attribute; its file name is pipe-index.png
pipes.index.ts
This image has an empty alt attribute; its file name is explorer-module.png
explorer.module.ts

The Application of Pipe to Paginator and Virtual Scroll with Angular Material 7

You can find about installation step of Angular Material here at https://material.angular.io/guide/getting-started.

This image has an empty alt attribute; its file name is paginator-virtualscroll.png
virtual-scroll + paginator

As time passes, the amount of confirmed transaction increases. Finally, the web page can not display all of them. Hence, virtual scroll, newly featured in Angular Material 7, as well as paginator may be solutions here.

This image has an empty alt attribute; its file name is Screen-Shot-2019-05-04-at-18.39.47.png
transaction.component.ts

The

Looking into html syntax, built-in html components, which are <cdk-virtual-scroll-viewport> and <mat-paginator>, need to be used.

<cdk-virtual-scroll-viewport itemSize="10">
          <transaction-item
            *ngFor="let transaction of transactions | filtertransaction : searchText | slice : lowValue : highValue"
            [transaction]="transaction">
          </transaction-item>
          <br>
        </cdk-virtual-scroll-viewport>


    <mat-paginator
      [length]="transactions.length"
      [pageSize]="pageSize"
      (page)="pageEvent = getPaginatorData($event)">
    </mat-paginator>

Conclusion and my Thought

In this project, the most favourite part in Angular is modularity. This results in separate beautiful modules, and it is convenient for developers to go back to read, debug, fix and scale new features.

Last but not least, I would like to mention that since the project is not mature, and I am happy welcomed to any improvement, if you, readers, want to comment it out. Happy coding!

Related posts