Todd Motto

Todd Motto

Owner, Ultimate Angular

Stateless Angular components
Feb 8, 2016
2 mins read
Edit post

There were a tonne of interesting changes happening in the beta and release candidate phases of AngularJS 1.5, one of them was the introduction of the Component method, which saw one-way bindings also introduced. We’ve also got the power to create stateless components.

What is a stateless component?

In React, we have stateless components that merely serve as a template that we want to clone and just pass data into, no state or Model is manipulated inside of them.

Stateless components in Angular

With the official 1.5 release, we can create stateless functions very similar to React’s implementation, and I love this.

Let’s assume we have a list of people, and we want to render their name and age using some sort of template to iteration over the collection.

When using the .component() method, we might create something like this:

// usage: <name-component></name-component>
var NameComponent = {
  bindings: {
    name: '=',
    age: '='
  },
  template: [
    '<div>',
      '<p>Name: {{$ctrl.name}}</p>',
      '<p>Age: {{$ctrl.age}}</p>',
    '</div>'
  ].join('')
};

angular
  .module('app', [])
  .component('nameComponent', NameComponent);

Let’s add some data to another Controller and actually render this awesome component.

Please note: this example is using version 1.5.0-rc.0

Ummm, why isn’t it rendering my values? Argh!

At this point, we were all rushing to try out the new .component() method in the beta or rc stage, and realised to make any of this new Directive abstraction we need to bind a Controller to it (because of the underlying implementation):

// usage: <name-component></name-component>
var NameComponent = {
  bindings: {
    name: '=',
    age: '='
  },
  controller: angular.noop, // or function () {} whatever
  controllerAs: '$ctrl',
  template: [
    '<div>',
      '<p>Name: {{$ctrl.name}}</p>',
      '<p>Age: {{$ctrl.age}}</p>',
    '</div>'
  ].join('')
};

angular
  .module('app', [])
  .component('nameComponent', NameComponent);

And now it renders:

Okay, well that’s extremely annoying, I need to bind a controller and declare the controllerAs property to get things to render.

So we ended up adding these empty Controllers to make things “work”, which isn’t pretty.

1.5 stable saves the day

The ability to not specify a Controller is available in the stable AngularJS 1.5 release! This means we can do exactly this without a Controller:

// usage: <name-component></name-component>
var NameComponent = {
  bindings: {
    name: '=',
    age: '='
  },
  template: [
    '<div>',
      '<p>Name: {{$ctrl.name}}</p>',
      '<p>Age: {{$ctrl.age}}</p>',
    '</div>'
  ].join('')
};

angular
  .module('app', [])
  .component('nameComponent', NameComponent);

And breathe, sanity is restored. Just like passing in props in React, we have the ability to merely pass properties into Angular components.

We no longer need a Controller as we were getting used to in the release candidate stages of the .component() method.

Voila:

Components can now just act as stateless templates, and that’s awesome and lightweight.

Caveats

The only caveat to this implementation is being forced to use $ctrl in your templates, which kind of seems crazy as you’re not technically using a Controller. You could override it with the controllerAs property, but we’re back to the start then.

Feb 5, 2016

One-way data-binding in Angular 1.5

Angular is known for its powerful two-way data-binding, but with the new release of AngularJS...

Feb 11, 2016

$onInit and new "require" Object syntax in Angular components

The component() helper method shipped with so many great features to take us even closer...