README: Angular 2 has changed significantly since this post was written. As such, please do not use this code verbatim. Instead, focus on the concepts below and then map them to the new syntax and API of Angular 2.0.0.
Welcome to the second post in our series on Angular 2. If you missed the first post, check out the quick Intro to Angular 2.
In this post, we are going to talk about Components, which elegantly replace the mix of controllers, scopes, and directives from Angular 1.
The death of scope
If you missed Igor and Tobias’ great talk at ngEurope in October, they quite dramatically proclaimed the death of a variety of Angular 1 concepts, including controllers and $scope
. I was there, I and remember the gasps and nervous laughter from the crowd as a series of ominous gravestones flashed on the screen:
The uproar from the broader community was immediate, with scathing comments, high-profile departures, and plenty of overly-dramatic banter to make it really exciting.
Though it made for good TV, the reaction was unwarranted. Those new to Angular 2 quickly see how the new component model is a lot easier to use than what we had in v1.
The “Component”
Angular 1 wasn’t built around the concept of components. Instead, we’d attach controllers to various parts of the page with our custom logic. Scopes would be attached or flow through, based on how our custom directives encapsulated themselves (isolate scope, anyone?).
I don’t really know how to describe the model in v1, but it wasn’t like any other hierarchical system I’ve ever used. We’d just “attach” behaviors to various parts of our page and then have to deal with the complicated meta-structure created by our directives, controllers, and scopes.
To add logic to the page, we’d have to decide between building a controller or a custom directive.
In version 2, Angular drops all of this for a much cleaner, more object-oriented Component model.
Our first component
If you’ve ever written Java, C#, or any other language with strong OO patterns, you’ll immediately understand a component. It’s just a class that represents an element on the screen, with member-data that influences the way it looks and behaves.
Just like a JComponent
subclass in Java (Swing), or a Control
subclass in Windows Forms development.
Let’s see an example:
import {Component} from '@angular/core'
@Component({
selector: 'my-component',
template: '<div>Hello my name is {{name}}</div>'
})
export class MyComponent {
constructor() {
this.name = 'Max'
}
sayMyName() {
console.log('My name is', this.name)
}
}
This creates a new component called MyComponent
, which will be identified in markup as <my-component>
, just like restrict: 'E'
did in v1.
We can specify a template for the component with the template
property in @Component
annotation (annotations are an es6 extension added by both AtScript and TypeScript, though only TypeScript will be relevant going forward).
Member data
If we look closer at the example above, we don’t see $scope
anywhere. Instead, we see this.name = 'Max'
, and a member function (“method”) called sayMyName()
. If you’re familiar with Controller As syntax in v1, the use of this
will look familiar to you.
Even so, this is different. When our component is “instantiated” and rendered on the page, we have an instance of our component. We can modify the instance data of that component, call methods on it, and pass it around to other components. It’s just an object!
More tangibly, imagine we have a Button
component. The component has a this.title
for the text of the button, and a click handler. Previously, we’d either build a new directive
for the button, maybe add an isolate scope with some events and two-way data bindings, or get lazy and just attach a controller to it (or one of its parents). With Angular 2 components, we get a natural combination of all of these concepts: our Component has encapsulated instance data (much like isolate scopes), event handlers (much like methods attached to scopes), and a template (much like directives).
We can even inherit from other components or attach components through attributes, and access parents and siblings (more on that in a future post). This is a far easier, less error-prone way to replace require
from directives in v1.
ngApp?
In the previous post, we briefly mentioned the bootstrap process, the process by which an Angular 2 app powers itself up. In v1, we had ng-app
, or we could manually bootstrap. In v2, there isn’t an ng-app
. Instead, we provide our own root Component from which we want to start the app:
<app></app>
which would look like this as a v2 component:
@Component({
selector: 'app',
templateUrl: 'main.html'
})
class MyApp {
constructor() {
console.log('App Start')
}
}
bootstrap(MyApp)
What we’d often see in Angular 1 was ng-app
and ng-controller
used on the same element, like this:
<body ng-app="myspace" ng-controller="AppCtrl">
Then, our AppCtrl
would create some root scope data that our child controllers would access and/or extend.
In v2, we get all of that in one Component.
I really like this change. If you think about your document layout, it’s really just a tree. The root shouldn’t be any different than every other element, even though it was in v1.
With the change to the component model, we need to change our mindset a bit. Instead of attaching our custom logic to the page with controllers, we put that logic into components. If we want a certain part of the page needs business logic, we create a new component for it. If we are using an existing component but want to attach behavior to it, we can extend it.
Annotations
Let’s dig in a bit to the @Component
annotation above. If you recall, these are extensions on ES6, which are becoming part of TypeScript which Angular 2 will use.
Basically, these annotations allow us to attach information to our component. We can configure the selector our Component will look for to instantiate itself (like <my-component>
), and also set the template.
@Component
is the core annotation, and has a few important parameters:
@Component({
selector: 'my-component',
providers: [MyService],
// Url based template
templateUrl: 'main.html',
// Inline template
template: `
<div>
<button></button>
<ng-content></ng-content>
</div>
`,
directives: [Button],
})
The selector
param is the replacement for the auto-naming system of directives in v1 and is now explicit: you must set it to exactly what you want the new component to be named in markup. It works much like querySelector
.
The providers
param is part of the new Dependency Injection system, and configures which services we want to inject into our component (more on this in a later post).
We can use provide a template either inline, using template
, or point to an external file using templateUrl
. This similar to how we defined templates for custom directives in Angular 1. Notice the use of the awesome new backtick Template strings in ES6 that let us easily create multi-line templates!
We also reference the child directives we want to enable so they are compiled and instantiated (I hope this changes in the future so you don’t have to explicitly specify child directives).
Finally, we should note the <ng-content></ng-content>
tag in our template. This is the new “ngTransclude” and specifies where child content will be injected. You can have multiple ones and target different spots to include child content (more on this in the future!)
Conclusion
A lot is changing in Angular 2, and few things as dramatically as the way we build and specify components on the page.
Though it’s scary to move on from our beloved scopes, controllers, and directives (concepts that we worked so hard to learn and learn to love), it’s really a wonderful thing. With the new component model, Angular is moving into much more familiar OO territory, and is setting itself up to work with the future of web standards, like Web Components and Shadow DOM.
Once you get used to the new model, it’s hard to go back. I think the community will learn to embrace the changes and appreciate how they make Angular 2 so much better.
In our next post, we will talk about “New-way” data binding: the untimely death of 2-way data binding! Stay tuned.
54 Comments
Awesome intro tutorial. The new angular kinda reminds me a little bit about react, which is good.
the new angular reminds about Adobe Flex 4 – welcome to 2010 !! 🙂
agreed! lot’s of things are starting to look like Flex, see Polymer!
agreed!
I have the same feeling. Googled it. And found this post!
This series is awesome!!
Helping us to move towards Angular 2 Smoothly.
Thank you
Really starting to like Angular 2. I can definitely see advantages.
Ionic have demonstrated the very best that can come out of (F)OSS development – an awesome framework, best-in-class, driven by talent, energy and seemingly good teamwork. The numbers speak for themselves as do the quality of many of the apps produced with Ionic.
Angular2, however, demonstrates one of the biggest problems with (F)OSS development, namely the lack of accountability towards an installed base – one of the nicer comments I read were: “Wow. I do not envy the person who has to tell the boss that the entire project has to be scrapped by the end of 2015 or face going unsupported for the next 15+ years.”. On top of that Typescript is a language with mixed receptions.
What I would like to know is what the Ionic team is thinking in terms of migration. Is it ‘scrap the old stuff and reprogram’ or are there any realistic means of reusing any factory, service, controller or template code? And if not; for how long will Ionic 1.x be supported and how?
In ng-conf, we have made a commitment to support v1 while significant people are still using it. So if you have an app in v1, you can stay using v1 and you will be supported, no need to upgrade.
Thanks for the update and the commitment.
Ionic 1.x will continue to be supported after Ionic2 comes out, same as Angular 1.x. Since Ionic2 is not completed yet we haven’t finalized a migration path, but there will be one for those who choose to upgrade.
Hi Adam,
This is what I want to hear. It is understood that it is early days. I take it that you will convey more information on the roadmap when ready.
Brgds, Palle
http://shouldifearangularjs2.com
Thanks for the write up, I could not have said it better myself.
So IONIC v1 will keep using angular v1 or will be soon migrated to v2? just to understand if i’ve to go back to jquery mobile or not 😛 or search another way of doing those apps.
Ionic v1 will stay on Angular v1, Ionic v2 will be using Angular v2. Breaking the API means incrementing the major version number (1->2), so that’s what’ll be happening here.
(Edit: It would be just really silly to give up and break Ionic v1 while it’s a perfectly working and valid version of Ionic in and of itself.)
How would “scope” inheritance work in Angular 2? Would components then inherit from other components? Wouldn’t all this deep nesting of inheritance be an anti-pattern?
So far as I know there is no scope inheritance. Which is probably a good thing as it makes it very difficult to reason about your code. I’ve stopped using scope inheritance completely in my 1.x apps.
It’s convenient but can blow up in your face as complexity goes up.
Is there any forked project of Ionic for Windows Phone support? I desperately need one! 🙁 What I understand from the official Ionic team is that they have no plans to start supporting WP “now”. They just have it in their least-priority TODO list. So I really appreciate anyone to introduce me to frameworks that support WP (I want only Ionic fork. Not others unless they are as good as Ionic).
Check out http://angularjs.meteor.com/ … watch the video. I think you’ll be able to create apps that will work on Windows Phone. They are also providing a meteor-ionic library. Pretty cool stuff.
Thanks for the link, Mark! I’ll check that out! 🙂
I was wondering if you were using the new router in ionic 2, or just waiting for a final release?
Otherwise how do you manage the routes/states of your app?
Hey. That depends on a few factors. We need a router w/ non linearity like you see with a tree of UINavigationControllers (to use the native iOS example). We have been involved with the new router discussion, so I’m really optimistic, just need to wait a bit on it.
That being said, we aren’t sure we want to do routing like we did in v1. It is pretty complicated, and we allow for pretty powerful deep linking that I’m not sure is worth the complexity (rarely do native apps deep link more than one history state deep, for UX reasons).
I’d personally like seeing URLs take less of a role in v2 for hardcore internal routing, instead favoring states and local routing (push/pop inside the closest navigation stack).
Stay tuned!
AngularJS 2 has some point of ReactJS… Will Angular2 + Ionic go on the React Native way?
Looks a lot like Java’s JSF; which is not a good thing.
How vague and abstract is the term “component”? Everything in the world is a component… Will it have complex component lifecycles also like JSF? These components need to be managed by something; which needs to be altered/extended on…
Annotations I would regard as an anti-pattern really. The original branding/popularity of POJO’s was to simplify stuff; now check any Java codebase and those simple plain old java objects have become a wishwash of hundreds of annotations (I’m not joking, I wrote plenty myself).
I’m particularly afraid this will be fun for some time learning a bit of new stuff, but looking back at your code two years later and I highly doubt it will feel clean or simple (not that angular 1 is clean or simple). Particularly with ES6 and ES7 in the future rendering typescript a bit unnecessary frankly.
Couldn’t agree more.
I believe the idea is to shift to a standard:
http://webcomponents.org/
Thanks for sharing
Are annotations required? This seems like a silly question, but it has been mentioned many times bye the Angular team that Angular 2 can be written with regular ES6. Any examples I have seen require developing in TypeScript simply because of the annotations.
You can use ES6 with annotations in both Babel and Traceur. Babel requires an additional plugin + configuration. Traceur requires configuration.
If you use JSPM + Traceur, add the following to config.js:
traceurOptions: {
“annotations”: true
}
Typescript is definitely not required, there’s just little/no documentation available for using Angular2 + ES6.
If you’re curious and want to see NG2 + ES6 in action check out my site:
https://github.com/evanplaice/evanplaice.com
nice descriptive post, but i would like to know does angular-v2 keep support the two-way data-binding or it would move two one-way data binding.
I am a bit worried that we are not seeing any es6 based tutorials.
To be honest at first I was really against some of the changes coming in Angular 2, but these posts are really helping me see why these changes are going to be great and you are making me excited to start implementing them in my projects. Thanks for the time and effort you put into explaining the new concepts Max!
Coming from an OO software background using Java and C#, this is great news 🙂
Much more comfortable territory.
I’m still waiting for information on services. Did I miss that?
This is good. Basically I needed a reason or a problem to solve to get into Angular, and mobile apps is a very good one.
Thanks you, I can’t wait for Angular 2
So, to use Angular 2 do we HAVE to use the Typescript transpiler? I hate working with transpilers. Is there no way to use Angular 2 as plain JS?
You don’t HAVE to use Typescript. You can use ES6 with Babel/Traceur + decorators enabled.
You can also write pure ES5 but I don’t recommend it. Decorators are basically high-order wrapper functions that add a lot of additional functionality. Trying to replicate the same functionality in pure ES5 requires a lot of extra work.
typescript isn’t really a transpiler… it just removes itself 🙂 (if you’re targeting es6)
Thanks!
Hi Max,
Thanks for your wonderful articles. I have a small doubt in Angular 2.0 as I started reading since yesterday.
When everybody writing a component they were writing the class just below the Annotation section as below. Since we will write so many components in our projects lets say if I write two components in a single file in that case how the component decides which class it has to use.
//Anotation section
@Component({ selector: ‘app’ })
@View({
url: ‘main.html’,
})
//Component controller
class MyApp {
constructor() {
console.log(‘App Start’)
}
}
The decorator applies to the class directly following. The same way as it works in Python.
As long as you do decorator first immediately followed by the class there won’t be any issues with putting multiple components in the same file.
Web Components
for those who want to try out components the easy way / online, no installations: I made a Codepen collection with starters for a few alternatives. Angular 2.0 and Aurelia are iframes to Plunker, as they require several .js ad .html files. Available starters currently for: Angular 2.0 preview, Angular 1.4 RC2 with ES6 via Babel (possible to create components 2.0 style), Polymer and of course Aurelia.
Feel free to fork from: http://codepen.io/collection/XPYmZa/
great info, thanks!
Nice post
I have been playing around with the incremental alpha releases and so far so good. Have added my poc work here in case you want to see some current examples: http://www.syntaxsuccess.com/viewarticle/angular-2.0-examples
These Angular 2 posts are a great resource for understanding the changes from v1. Please continue this series of blog posts!
Just finished learning ionic/angular and was about to start building app with ionic1/angular1 and all of a sudden things chnged.but coming from OO background its looking better. Plus your blog is making it really easy to learn the new angular.
Thanks
I’m doing something with Angular 2, and I’m wondering if I can change the directives array base on what i want. the the screen shoot may be show what I mean. thank you!!
try
[directive1, directive2, directive3]
does @View still apply? seems like you just specify the template right in the controller now? for RC1
I am having difficulty figuring out how to communicate between components – for instance how to add/remove classes in sibling components:
1) A list of cards with checkboxes
2) On selection of two checkboxes
3) Add a class on a (compare) button on a header component
Thank for any help!
ng-content is like ion-content or different
313 Trackbacks