Basics 2: Blockchain Events & User Interface
Goal: We’ll add event listeners and show updates in a beautiful Nimiq-style UI.
» Skip tutorial and see the code.
Just Getting started? This tutorial is based on the ideas and code of Basics 1: Consensus, were we set up a minimal Pico Client that connects and syncs with the network but without much UI.
Our app needs some basic UI. And some more data to show.
Showing Statistics
Let’s add some plain HTML to show a status message and some network statistics such as
current block height, connected peers, and the amount of data going in and out.
We’ll use <span>
tags with IDs as placeholders to put the content in later.
<body>
<h1>Nimiq Demo App</h1>
<p>Status: <span id="message"></span></p>
<p>Current block height: <span id="height"></span></p>
<p>Network: <span id="network"></span></p>
</body>
In the start()
function, the Pico Client connects to the network and
establishes consensus.
See Basics 1: Establishing Consensus for details.
We define a shared variable nimiq
to keep references to client and network for later.
(More details on each part in the next tutorial.)
const nimiq = {}; // <-- this is the shared variable
async function start() {
// Code from tutorial "Basics 1: Establishing Consensus"
status('Nimiq loaded. Establishing consensus...');
// Three lines to connect to the network
Nimiq.GenesisConfig.test();
const configBuilder = Nimiq.Client.Configuration.builder();
const client = configBuilder.instantiateClient();
// Store references // <-- this part is NEW!
nimiq.client = client;
nimiq.network = client.network;
}
Besides the status()
function from the previous tutorial, we prepare two event handlers:
// A convenient shortcut for 'document.getElementById()'
const $ = document.getElementById.bind(document);
function status(text) {
$('message').textContent = text;
}
// Moving the code from 'start()' into its own handler function
function onConsensusChanged(consensus) {
status(
consensus === Nimiq.Client.ConsensusState.ESTABLISHED
? 'Consensus established.'
: 'Establishing consensus...'
);
}
// Head change means a new block got mined, updating the 'head' of the blockchain
async function onHeadChanged() {
const height = await nimiq.client.getHeadHeight();
$('height').textContent = height;
// Show some network statistics
const stats = await nimiq.network.getStatistics();
const { totalPeerCount, bytesReceived, bytesSent } = stats;
$('network').textContent =
`${totalPeerCount} peers connected,
${bytesSent} bytes sent,
${bytesReceived} received.`;
}
The first handler, onConsensusChanged
, will only print out a little note when consensus has been established.
The code was part of start()
in the previous tutorial.
The second handler, onHeadChanged
, is more interesting.
It will be called each time a new block gets added to the Nimiq blockchain.
When this happens, we will update the UI with the new current block height as well as some network statistics.
Now, let’s connect the handlers to the events by adding event listeners in start()
:
async function start() {
// ... previous code
client.addConsensusChangedListener(onConsensusChanged);
client.addHeadChangedListener(onHeadChanged);
}
Final step: initialize the Nimiq client library passing our start
function
that will be called once everything is loaded and ready.
You will have this line already if you continued from tutorial 1.
Nimiq.init(start);
The logic is defined, let’s make it look good!
Beautiful UI with Nimiq Style
Nimiq Style requires two CSS files to be added to <head>
:
<link href="https://fonts.googleapis.com/css?family=Muli:400,600,700" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@nimiq/style@v0/nimiq-style.min.css" rel="stylesheet">
Learn more about Nimiq Style:
The Nimiq Style CSS framework provides classes that are prefixed with nq-
.
Setting nq-style
on <body>
will automatically style general elements such as paragraphs and links.
nq-card
will create a box layout to separate content.
<body class="nq-style">
<div class="nq-card">
<div class="nq-card-header">
<h1>Nimiq Demo App</h1>
</div>
<div class="nq-card-body">
<p>Status: <span id="message"></span></p>
<p>Current block height: <span id="height"></span></p>
<p>Network: <span id="network"></span></p>
</div>
</div>
</body>
To have the box full-screen for mobile and neatly centered for desktop,
add these styles to a <style>
tag in the <head>
section of your markup:
.nq-card {
margin: 0 auto;
}
@media(min-width: 800px) {
.nq-card {
margin-top: 10rem;
}
}
Check it out:
That’s starting to look more like a real UI. And just with a few lines of code!
» Run and modify this code live.
What’s next?
This short demo could be extended to a little blockchain stats viewer. You could add:
Global hash rate: Want to calculate and show the global hash rate?
Get the difficulty from the latest block in onHeadChanged
with the client.getHeadBlock()
method
and have a look at the nano network API
to turn the difficulty into the estimated global hash rate.
And while you’re at it, how about adding some graphs? :)
Error handling: Before publishing your app, you should add some error handling. A basic version could be something along the lines of:
function onError(code) {
switch (code) {
case Nimiq.ERR_WAIT:
alert('Error: Nimiq is already running in another tab or window.');
break;
case Nimiq.ERR_UNSUPPORTED:
alert('Error: Browser not supported.');
break;
default:
alert('Error: Nimiq initialization error.');
break;
}
}
// Nimiq.init() accepts an error handler as a second parameter
Nimiq.init(start, onError);
Note: Basic error handling will be part of the code from the next tutorial.
Continue the tutorial: Basics 3, Sending and Receiving Transactions »
Find more help and documentation in the Nimiq Developer Center. Share your ideas and feedback on the Nimiq Community Forum, you’ll also find a dedicated section for discussions and ideas. Or get in touch at sven@nimiq.com.