Best practice for creating a widget

Widgets are essentially a mini-application within a web app that provides specific functionality. This tutorial will show you how to create a new widget with some basic HTML elements and functionality that you can add to the Wittos portal.

What you'll find in this tutorial:

  1. In the first part of this tutorial you will create a HTML skeleton for the widget
  2. In the second part we take advantage of the Project SWIFT Open Innovation APIs and show some information about ongoing train routes

Part 1

Connecting the widget to the portal

To configure and publish your widget on the portal we need an empty div element with an id and a script tag that loads your JavaScript code.

We use JavaScript to render content in the widget. That means that the entire DOM of your widget will have to be built in a JavaScript file. Host this file on a server and use the script tag to load it into your widget.

<div id=”thisIsAnExampleWidget”>
	<!-- Your widget will be contained here -->	
</div>

<script type="text/javascript" src="https://www.example.org/myWidget.js"></script>

Use a relevant id to avoid accidentally targeting another widget.

<!-- Do -->
<div id=”superSpecificNameForThisWidget”>
<!-- Don't -->
<div id=”AppWidget”>

Javascript

To avoid overriding or leaking variables into the global scope, wrap all your JavaScript code in an IIFE (Immediately Invoked Function Expression)

(function(){

//Everything goes in here

})()

Target the div that will hold the content of your widget:

const myWidget = document.getElementById('thisIsAnExampleWidget');

You can also use jQuery to select HTML elements and manipulate the DOM:

const myWidget = $('#thisIsAnExampleWidget');

For a more general approach, we will continue to use plain JavaScript in this tutorial.

Adding a heading element to the widget

const headingElement = document.createElement('h1');

//Insert the created element inside the div that contains your widget:
myWidget.appendChild(headingElement);

//Since it doesn't contain any text, the h1 will be an empty element
<div id="thisIsAnExampleWidget">
	<h1></h1>
</div>

//Let's add some text to the h1 by using the [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) property of the element
headingElement.innerHTML = 'Hello World!';
Add Heading Demo

Adding a button:

const widgetButton = document.createElement('button');
myWidget.appendChild(widgetButton);

//The text inside the button
widgetButton.innerHTML = 'This is a button';
Add Button Demo

Let's give this button something to do. Like adding a new paragraph everytime you click it

//Add a click event listener for the button
widgetButton.addEventListener('click', function() {
const widgetParagraph = document.createElement('p');
widgetParagraph.innerHTML = 'Lorem ipsum dolor sit amet';
myWidget.appendChild(widgetParagraph);
});

//Change the text inside the button
widgetButton.innerHTML = 'Add a paragraph';
Add Event Listener for the button

Adding an image:

//Create a div to hold the image and insert it into the widget
const imageDiv = document.createElement('div');
myWidget.appendChild(imageDiv);

//Create the image element, [set its src attribute](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute) and append it to its div
const widgetImage = document.createElement('img');
widgetImage.setAttribute('src', 'https://via.placeholder.com/150x100');
imageDiv.appendChild(widgetImage);
Add Image Demo

Styling

Add CSS to your widget

Create a style element that will hold your CSS

const widgetStyle = document.createElement('style');

//Use [.insertBefore](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore) instead of [.appendChild](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) if you want to add the element at certain position rather than at the end of your elements list
myWidget.insertBefore(widgetStyle, myWidget.childNodes[0]);

Always add the id of the div that contains your widget in front of the CSS selectors, otherwise you will override the styling of the target page

widgetStyle.innerHTML = `#thisIsAnExampleWidget h1 {
		color:red;
	}
	#thisIsAnExampleWidget img {
		border-radius: 20px;
	}
	#thisIsAnExampleWidget p {
		color: green;
	}`;
Add CSS Stlying Demo

Part 2

Using the Project SWIFT Open Innovation APIs in the widget:

You can find out more details about the Project SWIFT Open Innovation APIs and how to use them on the documentation section.

First, we add a button that will show information about one of the active trains when it gets clicked. Then we will create a paragraph element that will contain this information.

const trainButton = document.createElement('button');
trainButton.innerHTML = 'Get train info';
myWidget.appendChild(trainButton);

const trainInfo = document.createElement('p');
Add Button to Retrieve Train Data Demo

Next, we will make a request to the API and retrieve data when a user clicks the "Get train info" button. To make the request you need a subscription key which you can find in your Wittos Portal profile page.

trainButton.addEventListener('click', function(){
	const xhr = new XMLHttpRequest();
	const key = "YOUR_KEY";
	xhr.responseType = 'json';
	xhr.open("GET", `https://wittos.azure-api.net/projectswift/trains?subscription-key=${key}`);
	xhr.send();
	xhr.addEventListener("readystatechange", function(){
		if(this.readyState === 4) {
			let trainNumber = xhr.response.trains[0].train_number;
			let trainStation = xhr.response.trains[0].station_code_to;
			let trainArrival = xhr.response.trains[0].scheduled_arrival_time;
			trainInfo.innerHTML = `Train number: ${trainNumber} will arrive at the ${trainStation} station at ${trainArrival}`;
		}
	});

	myWidget.appendChild(trainInfo);
});
Train Data Demo

Recommendations:

  • On the portal, the maximum height of the widgets is set to 330px, out of which 14px are used for padding (padding-top: 7px, padding-bottom: 7px). A widget taller than 316px will have a scrollbar on it's right side. If you would like your widget to be fully visible without having the users scroll, keep that size in mind.
  • To ease the development of the widget and to make sure that it is going to fit properly on the portal, you can use a tool that most modern browsers offer in their developer toolset that simulates different sizes/resolutions of devices (Responsive Design Mode in Firefox and Safari, Device Mode in Chrome, Emulation in MS Edge, etc.) and set it to a height of 316px.
  • In this tutorial we take advantage of a few ES6 features. For example, we use Template Strings to write CSS rules because it allows us to write multiline stings without using a \(backslash). Template Strings use back-ticks (``) rather than the single or double quotes we're used to with regular strings. Unfortunately, Template Strings and other ES6 features are not completely supported by older browsers like Internet Explorer. If you would like to ensure compatibility with these browsers, use a JavaScript transpiler like BabelJS to easily convert your ES6 JS code to ES5 compatible code.