Fundamentals

Web App Building Blocks Part 2

Building Deeper JavaScript Interfaces with jQuery

Rob Bell

Issue 20, March 2019

This article includes additional downloadable resources.
Please log in to access.

Log in

Make your interface do more without a server.

In the first installment, we covered the basics of using HTML and created a few different basic web servers using an Arduino.

Before we push too much further into server-side functionality on the Arduino, we’re going to look at a few ways to control and handle data within the app itself.

The benefit of this front-end knowledge is it can be applied to virtually any server type, whether it’s an Arduino, a regular web server, or doesn’t even use a server at all!

SERVERLESS FUNCTIONALITY

One of the biggest advantages of a web app style setup is arguably the ability for things to happen in the app, which is then later synced to the server.

When we work in a metropolitan region, we rarely think about what life is like without the Internet. Three minutes without WiFi can feel like the beginning of Armageddon, as productivity halts, and we all wonder how we’re going to access our cloud services. Or we stare intently as our 4G connection shows barely one-bar of service, while we’re reminded about the lack of bandwidth as our apps grind to a halt with nothing but a loading wheel.

But the reality is, while the largest mobile network providers in Australia spruik their 1,000,000km2 coverage, the reality is dead-spots are everywhere. On the trains, in the country, in the valley, and sometimes even where you’d least expect it. Just recently, I took my kids to Taronga Zoo in Sydney, which is right on Sydney Harbour. You can literally see the Harbour Bridge, Opera House, and all the ferries transporting people across the water. But I was surprised to find barely enough mobile coverage to load any of my favourite apps.

This isn’t really an issue if I am merely posting photos to Instagram. But what if I‘m trying to do something more useful? What if a zookeeper was collecting statistics and needed to push them to the cloud? I’m sure they have WiFi in their air conditioned offices, but what about while they’re wandering outside in 42°C heat like the rest of us?

It’s applications like this, where mobile coverage (or any internet coverage) is limited, that really benefit from an offline operation. Do the work, sync when a connection is available. Great!

We’ll concentrate on the front-end (that is, the interface) side of things for this installment, and then complete things with the server-side processing next month.

MANIFESTS AND OFFLINE CACHE

Perhaps one of the best assets to web apps in recent years has been offline cache. These were a huge tool in creating instructions for what web apps should store in the browser’s memory. It gave us the ability to blur the lines between computer software and web pages.

Unfortunately, Google Chrome (and likely others) have deprecated manifest files for non-secure requests. This means that it’s not really feasible to run an Arduino web server with offline cache apps. You can theoretically serve your HTML package from a secure site, then have it contact a non-secure Arduino, but this will usually generate a myriad of warnings and prompts about what a bad idea it is to do so. As a result, SSL is generally beyond the scope of what we would use an Arduino web server for. So next month when we cover off Offline cache further, we’ll cover SSL with a more powerful web server, to work around the challenges it presents.

This SSL complexity presents an unusual conundrum for DIY IoT devices. Do you go to the extra effort of catering for SSL, or accept the risks that may be associated with non-SSL communications? There are libraries available for many ethernet shields and wireless modules, however, they often take up much of the memory we want to reserve for our own software.

How important is SSL for IoT? The answer is, it depends. If you’re transmitting sensitive data then SSL is absolutely imperative. However, if you’re merely reading a few DHT sensors, you may be happy to forgive the lack of security in your communications, because it doesn’t really matter if someone was able to snoop in on what you’re transmitting anyway. It’s now well known that even many commercial IoT devices have relatively basic security (or no security at all).

However, before we get to manifests and offline cache, let’s look at how we can stack events in the browser to batch our server requests with a sequence of data. This is fairly straightforward and can still achieve some great functionality before you even get into these more advanced ideas.

JAVASCRIPT AND CONSOLE LOG

If you’re new to JavaScript development, you’ll want to get friendly with the Developer Console. This provides you with a great place to see what’s going on with your code, and also output all sorts of things to when trying to develop your code. Most importantly, when you’re dealing with unknown data (or you’re just feeling your way around), it gives you a convenient space to output everything to, without interrupting your app. The associated developer tools also give you insight into how your app is running and find any bottlenecks.

developer console

One popular method for outputting values was using the “alert()” function, and at first glance, it’s a good idea. It’s universally supported and easy to implement. One caveat is that it immediately halts your program. While ever an alert dialogue is open, your software stops. No updates, no interactions, everything is frozen until it’s cleared. Naturally, this can be useful if this functionality is actually desired. It can indeed be useful for critical operations, where you must obtain user input in order to proceed.

JavaScript allows you to push text, values, and even arrays into the console using the built-in command “Console.log”. In Google Chrome (arguably the best choice for development), you can open up the Developer console by navigating to View -> Developer -> JavaScript Console. Whatever browser you’re using, it’s probably not far from there either.

console.log("Hello, this is the console log.");

You’ll get something like this:

log hello

Naturally, if you have an array, you can output it too.

var myArray = []
myArray.push(‘value 1’, ‘value 2’, ‘value 3’);
console.log(myArray);

You’ll get something like this:

myarray

It’s also interactive. For nested arrays and complex JSON data, you can drill down into child nodes. It’s MUCH easier than pushing through roughly outputted data.

The short story here is, make friends with your developer tools in the browser. They’ll save you all sorts of troubles, and expedite developments.

So let’s look at a few simple things we can do with data before anything is sent to the server.

SIMPLE EVENT STACKING

For this example, we’ll use jQuery in our HTML package to create a string that we parse to the server once we’re ready to complete.

Our examples in last month’s Fundamentals used AJAX for “behind the scenes” communication with the server, and that worked great. But this example takes things to the next level. No Arduino is required for these examples, as we’ll display all actions in the Console, as described previously.

We have created six buttons in our HTML file, to control three LEDs (theoretically). Three on and three off, with each button set representing a different LED colour. We also have a “submit” button at the bottom. This is because the buttons themselves don’t submit to the server. We catch them with our JavaScript, and only process them when the submit button is pressed.

sixbuttons

First up, we create our variable to hold our data, this will be an array, and we’ll store comma separated values for processing on the server once it’s time.

var queryCache = [];

Now we have a container for our data, we can start waiting for actions. Each time a button is depressed, we read the value of the button being pressed. This value is stored in HTML as the data-id. Attributes like this never used to exist in HTML (at least, not officially), however, they’re now commonplace to make life easy for precisely this type of function.

  <button data-id="red1" class="red">
RED ON</button> 
  <button data-id="grn1" class="green">
GREEN ON</button> 
  <button data-id="blu1" class="blue" >
BLUE ON</button> 

You can put just about whatever you want in the data-id attribute, but we’re keeping it simple (and a consistent character length, which we’ll explain later too, once we start handling things on the server).

Here’s the critical part of our JavaScript code:

$( "button" ).click( function(e) {
// prevent the browser’s default behaviour
  e.preventDefault();
//look up information from the "data-" attribute
  var press = e.target.dataset[‘id’];
// here we test to see if it’s our submit button
  if (press != ‘submit’) {
// we push the details of the button pushed 
// to the array storing our sequence
    queryCache.push(e.target.dataset[‘id’]);
    console.log(queryCache);
  } else {
// our submit button is being pushed
// where we would push our data to the server
// the data has been submitted
// clear the cache to start the next sequence
    queryCache = [];
    console.log(‘Submitting and emptying ‘ +
queryCache);
  }
} );

It’s deliberately over-commented so you can see precisely what’s doing what. Using the supplied HTML in a browser, you should be able to click the buttons and see something like the following.

log sequence

As you’ll quickly notice, each button pressed adds to the array. The array continues to grow until you hit submit. Normally this is where you would submit to the server, to do whatever it is you intended on the server.

Once the server tells us it’s all received and processed, we can clear the array to start the whole process again (here, we dump the contents to the Console so you can see that it’s been cleared).

WHERE TO FROM HERE?

Next month we’re going to implement server handling of these more complex events. We’ll break down the arrays and process the data as required. We’ll also add in some additional complexity on the front-end to add more control power to the app, allowing even more performance in the user interface.

Part 1