Ronaldo Vitto Lewerissa

Software engineering learning documentation.

Twitch Streamer App using AngularJs

twitch_streamer_api_app

I recently went to create a twitch streamer app. It wasn’t actually an app you can use to watch Twitch videos, it certainly can be done, but it was way to long for a CodePen app, and I was only trying to accomplish Free Code Camp’s project.

Anyway, the objective is to play around with Twitch API.

There’s a complete list of how you can handle the API on GitHub. It’s pretty neat and deep.

Take a peek if you're interested!

I integrate this project with Angular as it’s UI framework.

Nothing fancy though, only making use of routing and several directives to achieve SPA (Single Page Application).

Let me show you some of it’s code.

To build the app, you need to instantiate using angular.module() . You will almost always refer to your app using this method. Best way is to keep it inside a variable.

var app = angular.module('twitch_streamer', ['ngResource', 'ngRoute']);  

Inject several modules: ngResource and ngRoute.

We’re going to use ngResource to handle HttpRequest.

It’s a bit tricky due to cross domain issue. It’s this thing called ‘Same Origin Policy‘ , read it up if you’re interested. Even more, take a look on CORS.

Next up, you might want to configure your routings:

.when('/', {
    template: A,
    controller: 'mainController'
  })
  .when('/teams', {
    template: B,
    controller: 'teamController'
  })
  .when('/search', {
    template: C,
    controller: 'searchController'
  })
  .otherwise('/');
}]);

Where A:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <div ng-repeat="prop in result.featured">
      <div class="col-xs-12 col-sm-4 col-lg-2 video-wrapper">
        <h3 class="video-title">{{ prop.title }}</h3><img ng-src="{{ prop.stream.channel.logo }}" class="img-responsive center-block">
        <div class="video-content" ng-Class="{" online ": prop.stream.channel.mature}">{{ status(prop.stream.channel.mature) }}</div>
      </div>
    </div>
  </div>
</section>  

B:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <div ng-repeat="prop in result.teams">
      <div class="col-xs-12 col-sm-4 col-lg-2 video-wrapper" ng-hide="$first">
        <h3 class="video-title">{{ prop.display_name }}</h3><img ng-src="{{ image(prop) }}" class="img-responsive center-block">
        <div class="team-content"></div>
      </div>
    </div>
  </div>
</section>  

and, C:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <form ng-submit="search()">
      <input type="text " class="search-input " placeholder="search for channels " ng-model="input" />
    </form>
    <div ng-repeat="prop in result.channels ">
      <div class="col-xs-12 col-sm-3 video-wrapper " id="search-wrapper " ng-click="onContentClick() ">
        <h3 class="video-title ">{{ prop.display_name }}</h3><img ng-src="{{ image(prop) }} " class="img-responsive center-block ">
      </div>
    </div>
  </div>
</section>  

Pardon me for having an unseparated document for the templates.

Looks a bit nasty, don’t you think? 🙂 I put this up on CodePen so having a separate document is not an option.

If you decided to split things up, don’t forget to change template  to templateUrl .

To work on the HttpRequest, you need to set up a factory.

app.factory('HttpRequest', ['$resource', function($resource) {  
  var resource = $resource('https://api.twitch.tv/kraken/:query/:else');
  resource.search = $resource('https://api.twitch.tv/kraken/search/channels?q=:query');
  return resource;
}]);

Factories is similar to services and providers.

Both factory and service functioned to create objects so you can inject it to controllers or other services.

Factory returns an object that will be the one to be injected to your controllers, on the other hand a service act as a function constructor which will be instantiated on the background.

On that code, we name the factory HttpRequest and set an array of injected services.

Array is use to avoid problems related to JavaScript minification.

You see, Angular use this so called ‘dependency injection‘ which literally just passing object around.

To know which object you requested, they evaluate the string given in the function argument.

function($resource){ ... }  

You don’t put your own variable, instead you specify what services you want Angular to inject to your function.

In this case, you requested $resource service.

You might be wondering how this went through, well, JavaScript function is literally just object, and you might guess, object can be coerced into string using the built-in .toString() method.

This way, you can parse function and see what the arguments are.

Head on to the controllers.

I’ve built three separate controllers, each targets a different template.

First one is for the Featured page.

app.controller('mainController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.result = HttpRequest.get({
    query: 'streams',
    else: 'featured'
  });
  $scope.headings = 'Featured Channels';
  $scope.status = function(bool) {
    return bool ? 'Online' : 'Offline';
  };
}]);

Two services are injected to this controller. You can see that we use array to overcome the dependancy injection issue. String will not be minified as if to function arguments.

We tell Angular to put $scope  for the first argument, HttpRequest  for the second. In this case, the name of the argument doesn’t matter anymore.

Using the built-in HttpRequest , we haven’t actually called a request out to a server just yet. Using the .get()  method we initiate the request.

Previously we set a placeholder for our query:

Now we set the placeholder to the desired instruction. In this case, query will be replaced by ‘streams’ and so does else with ‘featured’.

Head on to the next controller:

app.controller('teamController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.result = HttpRequest.get({
    query: 'teams'
  });
  $scope.headings = 'Active Teams';
  $scope.image = function(obj) {
    if (obj.logo === null) {
      return 'https://cdn1.iconfinder.com/data/icons/simple-icons/256/twitch-256-black.png';
    } else {
      return obj.logo;
    }
  };
}]);

Nothing fancy, only a single request specifying the query placeholder, change the heading, and apply placeholder images for results in case images are not supported.

Okay then, next one!

app.controller('searchController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.headings = 'Search Channels';
  $scope.input = '';
  $scope.show = false;
  $scope.httpReq = function() {
    var a = HttpRequest.search.get({
      query: $scope.input
    });
    return a;
  };
  $scope.search = function() {
    $scope.result = $scope.httpReq();
  };
  $scope.image = function(obj) {
    if (!obj.logo) {
      return 'https://cdn1.iconfinder.com/data/icons/simple-icons/256/twitch-256-black.png';
    } else {
      return obj.logo;
    }
  };
}]);

Well, it’s actually pretty much the same with previous controllers, this time it handles the Search Channel page.

What differentiate this controller is only by the way it request and make use of the API. You definitely need to check on the Twitch API GitHub page if you’re bit curious about how these things work.

That’s all for the JavaScript, it all went around JavaScript only since markups are used as a template in this Angular app.

Little bit of the HTML peek:

<div ng-app="twitch_streamer">  
  <section id='navigation-bar'>
    <div class='header'>
      <div class='logo'> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Twitch_logo.svg/2000px-Twitch_logo.svg.png" class='img-responsive'> </div>
    </div>
    <div class="link-wrapper">
      <ul class="nav nav-pills nav-stacked">
        <li role="presentation"><a href="#/">Featured</a>
        </li>
        <li role="presentation"><a href="#teams/">Active Teams</a>
        </li>
        <li role="presentation"><a href="#search/">Search Channel</a>
        </li>
      </ul>
    </div>
  </section>
  <div ng-view></div>
</div>  

Haven’t taught myself about code style when doing this project, so this code style is a little random. No naming conventions like BEM (Block Element Modifier).

Anyway, cheers!

Written by Ronaldo Vitto Lewerissa

Read more posts by this author.