Angular JS Logo

Components are going to be the way to do things in Angular 2, but I’ve got plenty of apps that are still using Angular 1.x, so to make my code more re-usable (and to prepare for the eventual move to 2.x), I’ve been reworking my code to use components.  Not only that, but it seems that Angular 1.x will be around at least until the traffic to the Angular 2.x site has reached more than 50% (over the site for Angular 1.x).

The basics

Components are defined much like directives, but instead use a name and a definition object that defines what happens in the component:


angular.module("myApp")
  .component("myComponent",{
  bindings: {
    varName: '<', // indicates input mode, or data coming from outside the component
    varName: '@', // indicates that the element will be an attribute
    varName: '&', // indicates the element will be a function
    varName: '=' // indicates that we need two way data binding for this model
  },
  // you can also use controllerAs to access this model in the bindings
  controller: function() {
  // the default to access the model is $ctrl,
  // but with controllerAs you can name it something more recognizable
  },
  template: '<div id="mytemplate">This is a template</div>',
  // or use templateURL to define a particular template
});

That defines the basics of a component, and with a component, anything we define inside the controller portion of the definition object is available to us just as it would be in a standard .controller() definition.  For simple components, that is all you need. For more complex components, there are a few other built in methods that allow you to make sure the component won’t instantiate until all data-bindings are available ($onInit), or to keep track when models change ($onChanges), or to release event handlers and external resources ($onDestroy).

Example from one of my longest running projects (which I’m currently re-coding in Angular):


(function () {
'use strict';

angular
  .module('bcpApp.daily_office')
  .component('bibleReading', {
    bindings: {
    type: "@",
    value: "<"
  },
  controllerAs: 'br',
  controller: function($scope, $http, $stateParams, dataService ,$log) {
    var vm = this;
    var reading_type = null;
    if(vm.type == 'old_testament') {
      vm.reading_type = 'Old Testament';
    } else if (vm.type == 'new_testament') {
      vm.reading_type = 'New Testament';
    } else if (vm.type == 'gospel') {
      vm.reading_type = 'Gospel';
    }
  },
  templateUrl:  'public/templates/daily_office/html/bible_reading.html'
  });
})();

And the template that gets referenced:


<p><strong>The {{br.reading_type}} Reading</strong></p>
<p ng-repeat="reading in br.value track by $index">
<span ng-if="br.reading_type != 'Gospel'">
<em>Reader:</em> A Reading (Lesson) from: <strong>{{reading.reference}}</strong><br/>
</span>
<span ng-if="br.reading_type == 'Gospel'">
<em>Reader:</em> A Reading from the Gospel according to <strong>St. {{reading.book_name}}</strong><br/>
</span>
<span ng-if="reading.bracketed_reading && reading.full_bracket"><strong>[</strong></span>
<span ng-if="reading.paren_reading && reading.full_paren"><strong>(</strong></span>
<span ng-repeat="v in reading.passage">
<span ng-if="reading.first_chapter && $first"><strong>{{reading.first_chapter}}</strong></span>
<span ng-if="reading.second_chapter == reading.chapter && !$first"><strong>{{reading.second_chapter}}</strong></span>
<span ng-if="reading.chapter && !reading.first_chapter"><strong>{{reading.chapter}}</strong></span>
<span ng-if="v.verse == reading.paren_start"><strong>(</strong></span>
<span ng-if="v.verse == reading.bracket_start"><strong>[</strong></span>
<sup>{{v.verse}}</sup> {{v.text}}
<span ng-if="v.verse == reading.paren_end"><strong>)</strong></span>
<span ng-if="v.verse == reading.bracket_end"><strong>]</strong></span>
</span>
<span ng-if="reading.bracketed_reading && reading.full_bracket"><strong>]</strong></span>
<span ng-if="reading.paren_reading && reading.full_paren"><strong>)</strong></span>
<span ng-if="(do_readings.references.do_readings.ot_type == 'AND' && !$last)">
<br/><strong><em>&mdash;AND&mdash;</em></strong><br/>
</span>
<span ng-if="(do_readings.references.do_readings.ot_type == 'OR' && !$last)">
<br/><strong><em>&mdash;OR&mdash;</em></strong><br/>
</span>
</p>

And finally, the component call in the main app:

</pre>
<bible-reading
type="old_testament"
value="do_readings.references.do_readings.ot">
</bible-reading>

The main thing here is that the type attribute is a string, which is why the component references it as a string in the bindings section.  The value attribute is an array of objects that get passed from the main controller of the page that pulls in the component, and that is why the bindings reference it with the ‘<‘ as that indicates that it is data coming from outside the component itself.

There is a considerably more in depth view of components in Angular 1.5 by Todd Motto, who actually works for Google, so I refer you to his site for really getting a handle on components.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.