Morse Translator and Morse Lamp in vanilla JS

Morse Translator and Morse Lamp in vanilla JS

Hello Everyone! I hope you are doing well. In this two part blog I will show you how I built a Morse Translator and signal lamp in JS.

Why did I make this?

I was learning Javascript and had to make a fun translation app in order to learn using APIs and stuff. After making the Morse translator I thought why stop here and tried to make a signal lamp. Initially I failed because of the problem of delays in Javascript. But I kept trying and eventually did it. You can see my morse translator and lamp here.

Disclaimer: I am a web dev beginner and my methods may not be the best, also I decided to make the lamp without using async await syntax because why not?

Topics to cover

  1. API and JSON
  2. fetch API
  3. Promises
  4. SetTimeout function

I will not be covering HTML and CSS part as that will make this blog too long.

API

API is an acronym for Application Programming interface. Notice the word 'interface' here. That means it is a way of communication. Just like we use GUI and CLI to interface with applications, applications use API to communicate with each other.

Quoting Chris Hoffman's blog on HowToGeek:

Think of an API like a menu in a restaurant. The menu provides a list of dishes you can order, along with a description of each dish. When you specify what menu items you want, the restaurant’s kitchen does the work and provides you with some finished dishes. You don’t know exactly how the restaurant prepares that food, and you don’t really need to. Similarly, an API lists a bunch of operations that developers can use, along with a description of what they do. The developer doesn’t necessarily need to know how, for example, an operating system builds and presents a “Save As” dialog box. They just need to know that it’s available for use in their app.

In our project, we will use an API from funtranslationAPI allowing our application to communicate with the translation function. This API call will return JSON data.

JSON

JSON is a text-based data format following JavaScript object syntax. Even though it closely resembles JavaScript object literal syntax, it can be used independently from JavaScript, and many programming environments feature the ability to read (parse) and generate JSON.

  • Keep in mind that JSON data exists in form of a string. This is particularly useful when you want to transmit data across a network over http protocol. We will need to convert it to a native JavaScript object when we want to access the data.

fetch API

The Fetch API provides an interface for fetching resources (including across the network). In other words "fetch API" is a Javascript API (yes, API in Javascript) with which we can make http requests and get data from other computer (server). Also these requests are asynchronous but we will not talk about that here.
To get data using fetch, we only need the endpoint URL which is the URL that we can use to access the data provided by the web API.
Here is the URL endpoint for Morse translator API -

https://api.funtranslations.com/translate/morse.json

Part I : Making Morse Translator

As I will not cover HTML/CSS part here is a snippet so you have some idea about that and variables will not confuse you.

var btnTranslate = document.querySelector("#btn-translate"); // Button to click for translation  
var english = document.querySelector("#english"); // The text area where you enter the sentence in English  
var morse = document.querySelector("#morse"); // The text area where Morse code appears

Define the apiURL

var apiURL = "https://api.funtranslations.com/translate/morse.json?text="

Whatever we want to translate will be encoded and concatenated to this url.

AddEventListener

The addEventListener function attaches a listener to the target and when the desired event happens such as a click or a keypress, a specified action is performed.

addEventListener syntax target.addEventListener(type, listener);

btnTranslate.addEventListener("click",  translateHandler);

Note that you do not need to call the function in place of listener, you just need to provide its name or you can also write a whole unnamed function there.

Now let's make the translateHandler function but before that you need to know what the response will look like? If I send the request with a sample text like "Morse is fun", the response (if successful) will look like this-

  "success": {
    "total": 1
  },
  "contents": {
    "translation": "morse",
    "text": "Morse is fun",
    "translated": "-- --- .-. ... .     .. ...     ..-. ..- -."
  }
}

Before making the request, you will need to encode the sentence in a specific form and then make the request. The server will then process the request and your given parameter will be processed accordingly. example- Encoding "Morse is fun" results in

api.funtranslations.com/translate/morse.jso..

function translationURL(text) {
  text = encodeURI(text);
  return (URLText = apiURL + text);
}

function translateHandler() {
  let text = english.value;
  console.log(text);
  fetch(translationURL(text))
    .then((response) => response.json()) // The .json() method
    .then((json) => {
      var translatedText = json.contents.translated;
      console.log(translatedText);
      morse.innerText = translatedText;
    })

}

When the user clicks the button, translateHandler is invoked. It takes the value in english textarea and passes it in the translationURL function where an inbuilt encodeURI method encodes the text and then encoded text is then concatenated with apiURL.
A fetch request is made with the resultant URLText which returns a promise. In simple words, it means fetch() says "you can go ahead with the execution and don't wait for me; I promise that I will let you know when I get the data."
How would we tell fetch() what do with this data? By giving it a callback inside the .then() of promise. Actions inside .then() are performed when the promise returned by fetch gets resolved or rejected. It can take two arguments where the first one is performed on resolution and second is performed on rejection but we won't be covering that.

Remember that JSON exists as a string and we need to parse it to Javascript object? The json() method of the Response interface takes the response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON. That is it says "Don't wait for me to complete parsing; I promise I will let you know when I do it." Note that despite the method being named json(), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object (key-value pairs).

These .then() methods can be chained together after which they too return a promise. When the first .then() resolves it's promise i.e. parses JSON into JS object, the second .then takes the JS object and the translatedText is found by traversing the object. Since the translated attribute is present within the contents object, we can refer it as json.contents.translated. Then we simply change the output text area's text with innerText method to the translatedText.

Oh! forgot to mention that Funtranslation APIs are free to use, but they have a limit for the number of times requests can be made. Once you excede this limit, it will give you an error. To catch that error we make an errorHandler function.

function errorHandler() {
  console.log("Some error occurred. Try again later.");
}

Add a .catch() method at the end of translateHandler.

function translateHandler() {
  .
  .
  fetch(translationURL(text))
    .then((response) => response.json()) 
    .then((json) => {
      ...
    })
.catch(errorHandler);

The catch() method returns a Promise and deals with rejected cases only, that means if the request does not get fulfilled then the errorHandler will be invoked.

The translator is now complete. Go ahead and do the CSS work yourself. I will end this blog here. In the next part we will learn more about the Morse code, promises and build the signal lamp. I hope this article helps you get a little idea about APIs and if it does please comment because knowing you helped someone is a pleasure.

Thanks for reading. Peace! ✌️