What does <div [x]="3" (y)="z()">
mean? The usual reaction for developers taking a look at the new Angular2 is: WTF? Luckily, it will take us only a few minutes to understand what the developers of Angular2 were thinking.
If you haven't tried it yet, the easiest way to play around with Angular2 today is either online with codepen.io or locally with a simple playground.
Let's get started!
Component({
selector: 'app-main'
})
.View({
template: `<h1>Hello</h1>`
})
.Class({
constructor: function() {}
});
Woohoo!
In Angular2 the whole "directive" <-> "world" communication method was simplified. A directive (now called 'component') can bind to "stuff" and it can emit events that the world can listen to.
We will initially only be playing around with the "template" part as that's where the weirdness happens.
Component({
selector: 'app-main'
})
.View({
template: `<h1>Hello</h1>`
})
.Class({
constructor: function() {
this.msg = 'world';
}
});
The backtick character in ES6 allows us to finally have multi-line strings in JS.
How would we go about connecting the msg variable to a div back in jQuery land? Update the property of that element with something like:
$('div').textContent = msg;
Well Angular2 is exactly the same, only with it we can bind them - make sure that any change to msg changes the div's content:
.View({
template: `<div bind-text-content="msg"></div>`
})
Well, that makes sense, but could we...
.View({
template: `
<div
bind-text-content="msg"
bind-style.background="'red'">
</div>
`
})
OMG! We can just run around binding HTML attributes directly to expressions! (Did you notice that we used 'red' inside ""? Yep, any expression, 'r' + 'e' + 'd' would do as well.
We got binding covered, so lets talk about Events. What happens when an input field changes?
<div
bind-text-content="msg"
bind-style.background="color">
</div>
<input on-keyup="color = $event.target.value" />
Again, familiar jQuery ground here, and as you can guess, any event can be bound to this way.
Of course in real code we will see things like:
on-change="changeColor()"
You are right, the samples all look different, and that is due to "syntactic sugar". Instead of writing bind-text-content you can just do [text-content] and instead of on-keyup use (keyup).
<div [text-content]="msg" [style.background]="color"></div>
<input (keyup)="color = $event.target.value" />
Much better.
While a div is a cool component and all, real components will behave in a very similar fashion. They will have a bunch of "properties" that can be passed to them and they will emit a bunch of "events".
Creating Components will be the second part of this tutorial
Angular 2 adds another idea to its templating, "Local Variables". We can create a variable that exists only in the template's scope and make our code a bit cleaner.
<div var-my-div>Hello</div>
<input (keyup)="myDiv.style.background = $event.target.value" />
When we used var-my-div a new myDiv variable was created that references the component itself. We could later use it in our keyup function.
myVar
will not be visible inside the Component's Class instance!
With some syntax sugar we can turn that var-my-div into #myDiv
<div #my-div>Hello</div>
<input (keyup)="myDiv.style.background = $event.target.value" />
Lets start with a simple example
<template [ng-if]='true'>
<span>Hello</span>
<p>World</p>
</template>
The above should have failed when trying to run in the simple playground. The reason being - standard directives also need to be imported and injected to be used. For our example, it would mean adding the following:
At the top of the file:
import { NgFor, NgIf } from 'angular2/angular2';
And inside the @View decorator:
directives: [NgFor, NgIf]
<template [ng-if]='true'>
<span>Hello</span>
<p>World</p>
</template>
Nothing fancy, and easy to understand. We are creating a ShadowDOM element and passing it to the NgIf directive. How about NgRepeat (Now called NgFor)?
<template ng-for bind-ng-for-of='[1,2,3]'>
<span>Hello</span>
<p>World</p>
</template>
The main difference is that there is a new input that NgFor sets on the template - which is the list on which to iterate over.
How do we gain access to the value and index of each row? The Angular2 way! The NgFor directive creates two new variables that we can use to bind to:
<template ng-for
bind-ng-for-of='[1,2,3]'
var-v='$implicit'
var-i='index'>
<span>Index: {{ i }}</span>
<span>Value: {{ v }}</span>
</template>
Lets add some Angular2 sugar:
<template ng-for
[ng-for-of]='[1,2,3]'
#v='$implicit'
#i='index'>
<span>Index: {{ i }}</span>
<span>Value: {{ v }}</span>
</template>
That is a bit long and ugly - that is why when the template has one root element (i.e. is wrapped with a single div ), we can turn things around:
<div template="ng-for #v of [1,2,3]; #i=index">
<span>Index: {{ i }}</span>
<span>Value: {{ v }}</span>
</div>
You probably noticed the strange "ng-for #v of [1,2,3]; #i=index" syntax. Angular2 does some pretty complex parsing for the template directive. We will talk about it in depth in a future post.
To make things even prettier - The special character * tells Angular2 that we are using a template and which directive to use to manage it:
<div *ng-for="#v of [1,2,3]; #i=index">..
<span>Index: {{ i }}</span>
<span>Value: {{ v }}</span>
</div>
Many different and interesting things, but this is the base you need to know to start using directives.
In the next chapter we will talk about building directives.
A big thank you to Yoni Weisbrod for proofreading this post.
More comments and discussion on HackerNews