Angular Dictionary

Using Dictionary API and Ajax

Posted on February 11, 2016 in angularseries, webdev
I had some some trouble with Cross-Origin XMLHttpRequests, so I had to switch to a different API. The code is roughly the same.

Dictionary API

I'm always looking for fun little API projects. I found DictionaryAPI on Programmable Web. It's free and simple, but they do limit your requests to something like 100/day.

I've always appreciated big, clean fonts and lots of space on web pages, so the idea of an ad-free minimalistic dictionary was appealing to me, so I made one using this API.

Getting the API working

When working with APIs, I first like to make sure I am getting the data I expect to get from each endpoint.

In this case, it was pretty easy, as Dictionary API doesn't require any authentication. I only had to use one endpoint:

http://dictionaryapi.net/api/definition/{word}

where "{word}" is the word I want to define. In response to this request you get something like this:

[{
  "Word": "submarine",
  "PartOfSpeech": "adjective",
  "Forms": [],
  "Definitions": [
    "Being, acting, or growing, under water in the sea; as, submarine navigators; submarine plants."
  ]
},
{
  "Word": "submarine",
  "PartOfSpeech": "noun",
  "Forms": [],
  "Definitions": [
    "A submarine plant or animal."
  ]
},
{
  "Word": "submarine",
  "PartOfSpeech": "noun",
  "Forms": [],
  "Definitions": [
    "A submarine boat; a ship that can travel under the surface of the water. Most such ships are ships of war, as part of a navy, but submarines are also used for oceanic research. Also called sub and (from the German U-Boot) U-boat.",
    "a submarine torpedo boat; called specif. submergible submarine when capable of operating at various depths and of traveling considerable distances under water, and submersible submarine when capable of being only partly submerged, i.e., so that the conning tower, etc., is still above water. The latter type and most of the former type are submerged as desired by regulating the amount of water admitted to the ballast tanks and sink on an even keel; some of the former type effect submersion while under way by means of horizontal rudders, in some cases also with admission of water to the ballast tanks.",
    "A stowaway on a seagoing vessel.",
    "A submarine sandwich."
  ]
}]

Dictionary Service

I was glad that I could use my newly acquired knowledge of Angular Services in this project. I made a very simple service called dictionaryService to handle api calls. In this case there was only one. Here's what my service definition looked like:

app.factory('dictionaryService', function($http){
  return {

    getDefinition: function(word){
      return $http.get('http://dictionaryapi.net/api/definition/'+word).then(function(result) {
        return result.data;
      });
    }

  }
});

Make Ajax Call on Delay

Perhaps the trickiest part of this project was creating a solid relationship between keyboard events and "Dictionary Service" calls. I wanted the definition of the word to show up quickly, but I didn't want to make any API calls that I didn't need (I have a limit of how many requests I can make per day). I decided it would be best to use some sort of delay tied to a keyup event.

After some googling I found out that Angular has a $timeout service that does exactly what I wanted. I injected the $timeout service into my controller and tied it to my word model, which is bound to the user's input.

Finishing Up

Here is the full code, with the "Dictionary Service" and $timeout service injected and implemented in the controller.

var app = angular.module('myApp', []);

app.factory('dictionaryService', function($http){
  return {

    getDefinition: function(word){
      return $http.get('http://dictionaryapi.net/api/definition/'+word).then(function(result) {
        return result.data;
      });
    }
  }
});

app.controller('mainCtrl', function($scope, dictionaryService, $timeout) {

  $scope.word = '';
  $scope.definitions = [];

  var timer=false;
  $scope.$watch('word', function(){

    if(timer){
        $timeout.cancel(timer)
    }  
    timer = $timeout(function(){
        if ($scope.word.length > 1){

          dictionaryService.getDefinition($scope.word).then(function(data) {
            $scope.definitions = data;
          });
        }
     }, 800) // delay after typing
  });

});

$(document).ready(function(){
  $("input").focus();
});


comments powered by Disqus