On Github Yonet / ForwardJS-Angular2
Created by Aysegul Yonet / twitter@AysegulYonet
Slides: bit.ly/ForwardJS-Angular2
Verify that you are running at least node v4.x.x and npm 3.x.x by running node -v and npm -v in a terminal/console window. Older versions produce errors.
npm install -g typescript npm install -g angular-cli@latestInstall the compiler and watch for changes to compile your ts code to JS.
var isDone: boolean = false; var lines: number = 42; var name: string = "Aysegul";
var notSure: any = 4; notSure = "maybe a string instead"; notSure = false;
// For collections, there are typed arrays and generic arrays let list: number[] = [1, 2, 3]; // Alternatively, using the generic array type let list: Array<number> = [1, 2, 3]; let projects: ProjectType[] =
export class ProjectType { id: number; name: string; url: string; }
let projects: ProjectType[] = [ {id: 1, name: 'Demo project', url: '...'} ]
// "void" is used in the special case of a function returning nothing function bigHorribleAlert(): void { alert("I'm a little annoying box!"); }
var f1 = function(i: number): number { return i * i; } // Return type inferred var f2 = function(i: number) { return i * i; } var f3 = (i: number): number => { return i * i; } // Return type inferred var f4 = (i: number) => { return i * i; } // Return type inferred, one-liner means no return keyword needed var f5 = (i: number) => i * i;Functions are first class citizens, support the lambda "fat arrow" syntax and use type inference.The following are equivalent, the same signature will be infered by the compiler, and same JavaScript will be emitted.
<!-- Interpolation --> <div>Hello, {{name}}!</div>
function chartDirective () { return { restrict: ‘E’, scope: { data:"parentData" }, link: link }; }; function link () {}
function chartDirective () { return { restrict: ‘E’, scope: {}, bindToController: { data:"parentData" } link: link }; }; function link () {}
<chart data="parentData"></chart>
<!-- Property Binding --> <chart [data]="parentData"></chart> <div [hidden]="hideMessage">I am a message</div>
<!-- Event Binding --> <button (click)="doStuff()">Do Stuff</button>It’s very easy to spot what is binding syntax and what is just a plain old attribute. The [] and () bindings are being tied directly into the component/DOM element properties and events. This means any public DOM event or property can be bound to with no additional coding!
<input [(ngmodel)]="message" placeholder="message">$event is the first argument.
<input type="text" #ref=""> <p>{{ref.value}}</p># creates a local variable. ref refers to the node itself.
<!-- Template Binding (ng-for, ng-if, etc...) --> <ul> <li *ngfor="let message of messages">{{message}}</li> </ul>ngFor is camelcase
//lib.js export function square(x) { return x * x; } // main.js import { square } from 'lib';
//lib.js export class Math{ this.square(){} } // main.js import { Math } from 'lib';
//main.ts import {bootstrap} from 'angular2/platform/browser'; import {AppComponent} from './app.component'; bootstrap(AppComponent, []);
document.addEventListener('DOMContentLoaded', function () { ng.platform.browser.bootstrap(MyAppComponent, [MyService, ng.core.provide(...)]); });
@Component({ selector: 'post-list' })Annotations define how we customize our components. Annotations provide the additional information that Angular requires in order to run yourapplication.
(function(app) { app.AppComponent = ng.core.Component({ selector: 'my-app', template: '<h1>My First Angular 2 App</h1>' }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));//Constructor function. //Annotations is a list attached to function.
<todo-list></todo-list> <time-picker></time-picker>Components are small reusable pieces of our UI, so that we can create a whole app without repeating our code.
@Component({ selector: 'catstagram', }) export Class Catstagram { constructor(){ this.posts = []; } }Declare reusable UI building blocks for an application. Each Angular component requires a single @Component and at least one @View annotation. The @Component annotation specifies when a component is instantiated, and which properties and hostListeners it binds to. When a component is instantiated, Angular: creates a shadow DOM for the component. loads the selected template into the shadow DOM. creates all the injectable objects configured with hostInjector and viewInjector.
@Component({ selector: 'catstagram', templateUrl:'posts.html' }) export Class Catstagram { constructor(){ this.posts = []; } }
@Component({ selector: 'catstagram', templateUrl:'posts.html', }) export Class Catstagram { constructor(){ this.posts = []; } }
angular .module('app') .directive('catstagram', catstagramComponent); function catstagramComponent () { var directive = { scope: { data:'=data' }, link: createComponent } return directive; function createComponent () {} }
angular .module('app') .directive('catstagram', catstagramComponent); function catstagramComponent () { var directive = { scope: { data:'=data' }, controller:catController, link: createComponent } return directive; function createComponent () {} function catController (){...} }
@Component({ selector: 'catstagram', templateUrl:'posts.html', }) export Class Catstagram { @Input() data; constructor(){ this.posts = this.data; } }
ng new forward5-app --style=sass
ng g component lists
<child [data]="dataValue"></child>
@Component({ selector:'child', template:'<p>{{data}}</p>' }) export class ChildComponent { @Input() data; }if data is primitive, when it changes the change detection runs if it is a reference, array, object,..., it will only run when the reference changes
<child [data]="dataValue"></child>
@Component({ selector:'parent', template:'<child (childevent)="onChildEvent($event)"></child>' }) export class ParentComponent { onChildEvent(ev){ console.log('Event fired',ev); } }if data is primitive, when it changes the change detection runs if it is a reference, array, object,..., it will only run when the reference changes
<child [data]="dataValue"></child>
@Component({ selector:'child', template:'<button (click)="onClick()"></button>' }) export class ChildComponent { @Output childEvent = new EventEmitter(); onClick(){ this.childEvent.emit('hello!'); } }
import { Injectable } from '@angular/core'; @Injectable() export class DataService(){ return [...]; }Services are just another class. We use appInjector in our component annotation to include it. No need for annotations for the service class.
import {ListsService} from '../listService.ts' @Component({ providers: [ListService] }) class PostList { constructor(private _listService: ListService) { this.posts = []; } getPosts(){ this._listService.getList(); } }Angular 2 provides a single API for injecting dependencies. All of them injected into the component’s constructor.
import { provideRouter, RouterConfig } from '@angular/router'; import { HomeComponent, ListComponent } fromt './..';Most routing applications should add a '' element just after the '' tag to tell the router how to compose navigation URLs. Bootstrap takes a list of injector bindings as second argument. Passing routerInjectables here basically makes all the bindings application-wide available.
import { provideRouter, RouterConfig } from '@angular/router'; const routes: RouterConfig = [ { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: 'home', component: HomeComponent }, { path: 'about', component: AboutComponent } ]; export const appRouterProviders = [ provideRouter(routes) ];
import { ROUTER_DIRECTIVES } from '@angular/router'; <nav> <a [routerlink]="['/home']">Home</a> <a [routerlink]="['/about']">About</a> </nav> <router-outlet></router-outlet>next to routerInjectables, there are other components that the router module exports. One of them is the RouteConfig class which can be used to decorate a component with routing capabilities.
export class DonePipe { transform(v, args) { return v && v.filter((item) => item.status === 'Done'); } }
// Instead of doing this: app.controller('CatController', function ($scope) { $scope.cats = []; }); // Do this: app.controller('CatController', function () { this.cats = []; });Use this instead of scope and use controller as syntax. Using controller as makes it obvious which controller you are accessing in the template when multiple controllers apply to an element. If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope, from inside the controller code. Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
"scope" is bound to the components
Having different kinds of scope, like isolated and non-isolated, can easily lead to issues. So it's best to keep things simple and focus on isolated scopes.import {Http, HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'http-app', viewProviders: [HTTP_PROVIDERS], templateUrl: 'people.html' }) export class PeopleComponent { constructor(http: Http) { http.get('people.json') // Call map on the response observable to get the parsed people object .map(res => res.json()) // Subscribe to the observable to get the parsed people object and attach it to the // component .subscribe(people => this.people = people); } }Http is available as an injectable class, with methods to perform http requests. Calling request returns an Observable which will emit a single Response when a response is received. https://angular.io/docs/js/latest/api/http/Http-class.html
- Slides - @AysegulYonet