facebook
Bob at Genuitec
Virtual evangelist at large. The face of Genuitec often appearing in graphics. Pen-name for our more shy writers of content.
Posted on Nov 7th 2017

With Bitcoin’s record-breaking surge past the $7000 mark, we thought this would the perfect time to build a cryptocurrency dashboard with Angular. Cryptocurrency is a digital asset designed to work as a medium of exchange, using cryptography to secure the transactions and to control the creation of additional units of the currency. While Bitcoin is the most popular digital currency, there are numerous other cryptocurrencies in existence.

In this tutorial, we will be creating a cryptocurrency dashboard using Angular and Angular IDE. On our dashboard, we will display the price, percentage change in 24-hour price, and percentage change in 7 day price of selected cryptocurrencies. You will learn about Angular fundamentals, like services and components – we’ll be creating several of these.You will also learn how to use RxJS Subjects.

Create New Angular Project

We’re going to be using Angular IDE through this tutorial, though you can use Webclipse or MyEclipse too, following exactly the same steps. Before beginning, do ensure you are in the Angular Perspective (Window > Perspective > Open Perspective > Other > Angular) for an optimum workspace layout and development experience.

In the new Angular project wizard (File > New > Angular Project), type `crypto-dashboard` as the project name – you may change the Node.js, npm and Angular CLI versions if desired.

cryptocurrency-dashboard-ss-3

Angular IDE will take a few minutes to set up the project, you can see the activities output in Terminal+. Once completed we see an output like in the image below:

terminal-original

Ready to see what your app looks like in a browser? With Angular IDE, it’s easy to run, or even debug an Angular application with just a few clicks. Use the Servers view, or the Run / Debug As actions to get started. Read this doc for more information.

Create Application Components

Taking a look at our UI design, we can identify two visible components, the search-filter box, and the list card. There is also an invisible component – the list itself. The components are highlighted in the picture below:

cryptocurrency-dashboard-ss-5

Now, let’s create the components. In the Component wizard (File > New > Component), type in search-filter as the Element name and click Finish.

Repeat the same steps to create the list-card, list and dashboard components too.

Tip: Notice how the commands to create the components are executed in the Terminal+ view, with the Angular CLI? Instead of using the Wizard, you could execute ng g component dashboard in the Terminal+ view (when in the app folder) to achieve the same result – our tooling is bidirectionally compatible with the Angular CLI!

Your directory structure, under the src/app folder should be as in the image below:

cryptocurrency-dashboard-ss-8

Add Bootstrap CSS and Font Awesome

Let us add Bootstrap CSS and Font Awesome to our project by updating the contents of `src/index.html`, add the code snippet below to the `head` section of the file:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css">
<link href='//fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.css" />

Install Angular-2-dropdown-multiselect

AngularX Dropdown Multiselect is used to create customizable dropdown combo in which multiple elements can be selected. Let’s install it by executing the command below in Terminal+:

`npm install –save angular-2-dropdown-multiselect`

In order to make the multiselect component available in our application, we need to import `MultiselectDropdownModule` in the `AppModule`. The entire source of  `src/app/app.module.ts` with this change is below:

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AppComponent} from './app.component';
import {SearchFilterComponent} from './search-filter/search-filter.component';
import {ListCardComponent} from './list-card/list-card.component';
import {ListComponent} from './list/list.component';
import {DashboardComponent} from './dashboard/dashboard.component';
import {FormsModule} from '@angular/forms';
import {MultiselectDropdownModule} from 'angular-2-dropdown-multiselect';
import {HttpClientModule} from '@angular/common/http';


@NgModule({
  declarations: [
    AppComponent,
    SearchFilterComponent,
    ListCardComponent,
    ListComponent,
    DashboardComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    MultiselectDropdownModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Here’s how the multi-select widget will appear in our final result.

cryptocurrency-dashboard-ss-10

The API

We will be using the API provided by coinmarketcap.com. To store the data returned, let us create a TypeScript class file named coin.ts in the app folder, with the following content. Note that you can use the Class wizard (File > New > Class) to create an empty class, and then replace the source with the snippet below:

export class Coin {
 id: string;
 name: string;
 symbol: string;
 rank: string;
 price_usd: string;
 price_btc: string;
 '24h_volume_usd': string;
 market_cap_usd: string;
 available_supply: string;
 total_supply: string;
 percent_change_1h: string;
 percent_change_24h: string;
 percent_change_7d: string;
 last_updated: string;
}

Create the AppService

In this tutorial, we will be using just one Angular Service, named AppService. In Angular, a Service is a broad capability encompassing any value, function, or feature that your application needs. In the Service wizard (File > New > Service), enter app as the Element name and click Finish.

AppService

AppService is a general-purpose class we will use to fetch data from the API, and pass that data on to components. We also use AppService to filter the data to display based on the options selected in the app. We could split this service into multiple services to abide by the single responsibility principle – but for simplicity, we won’t do that here.

Before we dive into the code, let’s get a few fundamentals down. First, RxJS is a reactive programming framework for Javascript. Core to understanding how to use RxJS is having a mental model of the observer pattern. The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependants, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Now RxJS Subjects are just like Observables, but they can multicast events to many Observers. In our service, we define four subjects.
  • `coinsSubject`: notifies its observers of coin data fetched from the API.
  • `filteredCoinsSubject`: its observers the filtered collection of crypto currency data. So,in the multiselect filter, only two crypto coins are selected then, the most recent value emitted by subscribing to `filteredCoinsSubject` will be an array of length two.
  • `apiSubject`: notifies its observers with a string message based on API actions.
  • `fiatSubject`: notifies its observers about the value of the selected fiat currency when it is updated.

The full code for `AppService` (`src/app/app.service.ts`) is below; explanations are in the comments.

// Imports
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import {HttpClient, HttpParams} from '@angular/common/http';
// Import Coin Shape file
import {Coin} from './coin';
const API_BASE_URL = 'https://api.coinmarketcap.com/v1/';

@Injectable()
export class AppService {
  private allCoins: Coin[]; // will hold unmodified data returned by the api
  private filteredCoins: Coin[]; // will hold data filtered from this.allCoins
  private filter: number[]; // will hold the array index of data contained in this. allCoins that should not be filtered out

  // A couple of RxJs Subjects very important for communicating across Angular Components
  coinsSubject: Subject<Coin[]>;
  filteredCoinsSubject: Subject<Coin[]>;
  apiSubject: Subject<string>;
  fiatSubject: Subject<string>;
  constructor(private http: HttpClient) {
    this.filter = [];
    // we initialize our subjects
    this.coinsSubject = new Subject();
    this.filteredCoinsSubject = new Subject();
    this.apiSubject = new Subject();
    this.fiatSubject = new Subject();
  }
  // this method loads market cap data from the API
  loadMarketCaps(fiat: string) {
    this.fiatSubject.next(fiat);
    const url = API_BASE_URL + 'ticker/';
    let params = new HttpParams();
    params = params.append('limit', '25');
    if (fiat !== 'usd') {
      // TODO: check if fiat is valid
      params = params.append('convert', fiat);
    }
    this.apiSubject.next('loading...');
    this.http
      .get<Coin[]>(url, {params})
      .subscribe(
      data => {
        this.allCoins = data; // store returned data
        this.announceCoins(); // trigger announcements
        this.filterMarketCaps();
      }
      );
  }

  filterMarketCaps() {
    this.filteredCoins = [];
    if (this.filter.length === 0) {
      this.allCoins.forEach((coin) => this.filteredCoins.push(coin));
    }
    if (this.filter.length > 0) {
      this.filter.forEach((i) => {
        this.filteredCoins.push(this.allCoins[i]);
      });
    }
    this.announceFilteredCoins();
  }
  announceCoins() {
    this.coinsSubject.next(this.allCoins);
  }
  announceFilteredCoins() {
    this.filteredCoinsSubject.next(this.filteredCoins);
  }
  updateFilter(filter: number[]) {
    this.filter = [];
    filter.forEach((elem) => {
      this.filter.push(elem);
    });
    this.filterMarketCaps();
  }
}

App Component

Update the content of `src/app/app.component.html` with the content below. We display the title in an `h2` element, and we set the dashboard component as a child view.

<div class="container">
	<div class="row">
		<div class="col-sm-6 col-sm-offset-3">
			<h2 class="text-center">{{ title }}</h2>
			<app-dashboard></app-dashboard>
		</div>
	</div>
</div>

Dashboard Component

The dashboard component will serve as a parent component for two components, the search component and the list component. Replace the contents of `src/app/dashboard/dashboard.component.html` with the code snippet below:

`<app-search-filter></app-search-filter>`
`<app-list></app-list>`

Since the scope of the service instance is the parent component and its children, we will create an instance of `AppService` in the dashboard component that will be shared by the `search-filter` component and the `list` component. To do this we update `src/app/dashboard/dashboard.component.ts` by importing `AppService`, and adding `AppService` to the providers array – which enables Angular’s Dependency Injector for `AppService`.

import {Component} from '@angular/core';
// import AppService
import {AppService} from '../app.service';
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css'],
  providers: [AppService] // provider setup
})
export class DashboardComponent {}

SearchFilter Component

The search-filter component is made up of a form containing two elements.

The first is a select element for choosing a fiat currency used in displaying the current worth of each crypto currency. The selected currency will be stored in a model aptly named `SelectedCurrency`. An `onChange` event listener will notify the app service to load data from the API.

The second element is is a multiselect dropdown that will enable us filter our choice of cryptocurrencies to display.

The code below goes in `src/app/search-filter/search-filter.component.html`:

<div>
	<form>
		<div class="form-group">
			<select id="selectedCurrency" name="selectedCurrency"
				[(ngModel)]="selectedCurrency"
				(change)="selectCurrency($event.target.value)" class="form-control"
				id="fiat">
				<option value="">Select fiat currency</option>
				<option *ngFor="let currency of currencies" value="{{currency}}">{{currency.toUpperCase()}}</option>
			</select>
		</div>
		<div class="form-group">
			<ss-multiselect-dropdown id="cryptocurrencies"
				name="cryptocurrencies" [texts]="myTexts" [settings]="mySettings"
				[options]="cryptoCurrOptions" [(ngModel)]="optionsModel"
				(ngModelChange)="filterChange($event)"></ss-multiselect-dropdown>
		</div>
	</form>
</div>

List Component

This component manages the display of a list of cards. One for each crypto coin data returned from the API. The coins model is an array of the data to be rendered by each coin.

Let us update the contents of `src/app/search-filter/search-filter.component.ts`:

import {Component, OnInit} from '@angular/core';
import {AppService} from '../app.service';
import {IMultiSelectOption, IMultiSelectSettings, IMultiSelectTexts} from 'angular-2-dropdown-multiselect';
@Component({
  selector: 'app-search-filter',
  templateUrl: './search-filter.component.html',
  styleUrls: ['./search-filter.component.css'],
  providers: []
})
export class SearchFilterComponent implements OnInit {
  currencies: string[];
  cryptoCurrOptions: IMultiSelectOption[];
  selectedCurrency: string;
  optionsModel: number[];
  // Settings configuration for the multiselect plugin
  mySettings: IMultiSelectSettings = {
    enableSearch: true,
    checkedStyle: 'fontawesome',
    buttonClasses: 'btn btn-default btn-block',
    dynamicTitleMaxItems: 5,
    displayAllSelectedText: true
  };
  // Text configuration for the multiselect plugin
  myTexts: IMultiSelectTexts = {
    checkAll: 'Select all',
    uncheckAll: 'Unselect all',
    checked: 'item selected',
    checkedPlural: 'items selected',
    searchPlaceholder: 'Find',
    searchEmptyResult: 'Nothing found...',
    searchNoRenderText: 'Type in search box to see results...',
    defaultTitle: 'Filter cryptos',
    allSelected: 'All selected',
  };
  constructor(private appService: AppService) {
    this.currencies = ['usd', 'eur']; // fiat currency options
    this.selectedCurrency = ''; // model to store selected fiat
    // array to hold names of cryptos to be used in filtering
    this.cryptoCurrOptions = [];
    // coinsSubject is a RxJs subject in our service that will notify us when the api has gotten data about crypto coins
    this.appService.coinsSubject.subscribe({
      next: (v) => this.updateCryptoOptions(v),
    });
  }
  ngOnInit() {
  }
  selectCurrency(newValue) {
    this.appService.loadMarketCaps(newValue);
  }
  filterChange(newValue) {
    // BUG method should not be triggered by filter select
    this.appService.updateFilter(newValue);
  }
  // This method creates an array of valid options for the multiselect plugin from an array of crypto coins
  updateCryptoOptions(coins) {
    this.cryptoCurrOptions = [];
    coins.forEach((coin, index) => {
      this.cryptoCurrOptions.push({
        id: index,
        name: coin.id.charAt(0).toUpperCase() + coin.id.slice(1)
      });
    });
  }
}

Let us update the contents of `src/app/list/list.component.html`:

<div class="list-cards pb-4">
 <app-list-card *ngFor="let coin of coins" [coin]="coin" [fiat]="fiat"></app-list-card>
</div>
<div *ngIf="!coins">
{{noDataMsg || 'Nothing to display'}}
</div>

The content of `src/app/list/list.component.css` is

.list-cards {
 display: flex;
 flex-direction: column;
 align-items: center;
}

In `src/app/list/list.component.ts`, we subscribe to three RxJS subjects in our Service –  `filteredCoinsSubject`, `apiSubject` and `fiatSubject`.

import {Component, OnInit} from '@angular/core';
import {AppService} from '../app.service';
import {Coin} from '../coin';
@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
  coins: Coin[];
  noDataMsg: string;
  fiat: string;
  constructor(private appService: AppService) {
    this.noDataMsg = 'Select fiat currency to get started';
    this.appService.filteredCoinsSubject.subscribe({
      next: (v) => this.updateCoins(v),
    });
    this.appService.apiSubject.subscribe({
      next: (msg) => this.noDataMsg = msg,
    });
    this.appService.fiatSubject.subscribe({
      next: (newValue) => this.fiat = newValue,
    });
  }
  updateCoins(coins: Coin[]) {
    this.coins = [];
    coins.forEach((coin) => this.coins.push(coin));
  }
  ngOnInit() {
  }
}

ListCard Component

The list-card component will display the market cap summary of a single cryptocurrency.

Let’s update the content of `src/app/list-card/list-card.component.ts` with this code:

import {Component, Input} from '@angular/core';
@Component({
  selector: 'app-list-card',
  templateUrl: './list-card.component.html',
  styleUrls: ['./list-card.component.css']
})
export class ListCardComponent {
  @Input() coin;
  @Input() fiat;
}

And the content of `src/app/list-card/list-card.component.html` with:

<div class="card text-center mt-4">
	<div class="card-body">
		<h2 class="card-title">{{ coin.id }}</h2>
		<h4 class="mb-0 pb-1">{{fiat.toUpperCase()}} {{
			coin['price_'+fiat] }}</h4>
	</div>
	<ul class="list-group list-group-flush">
		<li class="list-group-item">24 hours: <span
			[class]="coin.percent_change_24h.charAt(0)==='-' ? 'red' : 'green' ">{{
				coin.percent_change_24h }}</span></li>
		<li class="list-group-item">7 days: <span
			[class]="coin.percent_change_24h.charAt(0)==='-' ? 'red' : 'green' ">{{
				coin.percent_change_7d }}</span></li>
	</ul>
</div>

Running the Application

Okay, let’s run the application! Open Angular IDE’s server view (Window > Show View > Servers), right click on your project, and select Start Server. Angular IDE serves the application on localhost, port 4200 by default, so open http://localhost:4200 in your browser to see the running app. Alternatively, use the “Run/Debug application in Chrome”, context menu actions on the project to load your app in the browser automatically.

cryptocurrency-dashboard-ss-11

Angular Cryptocurrency Dashboard

Conclusion

We hope this article helped you understand how to interact with web services, and build a moderately complex UI in Angular, with Angular IDE. At $7000, it may be a tad late to buy some Bitcoin today, but Angular IDE can be had at a much lower price. Buy Angular IDE today – it’s an investment that’s sure to pay huge dividends in the short and long term. Remember, you can benefit from our Angular features in our standalone Angular IDE, as part of our Webclipse plug-in, or our fullstack offering, MyEclipse IDE.