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.
Table of contents
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:
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.
Free eBook
Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.
- Observables and Async Pipe
- Identity Checking and Performance
- Web Components <ng-template> syntax
- <ng-container> and Observable Composition
- Advanced Rendering Patterns
- Setters and Getters for Styles and Class Bindings
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:
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:
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.