Angular 2: Difference between revisions

From Han Wiki
Jump to navigation Jump to search
→‎@Component Annotation: remove ending bracket
add a link to Angular 2 by Examples
 
(10 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Data Architecture ==
[[Angular 2 by Examples]]


=== Observables (aka Reactive Programming) ===
= Running the app (via npm) =


* Promises emit single values, and streams emit multiple values
Compile just once. This executable binary is founder under <span class="shell">./npm_modules/.bin/</span> folder.
** callbacks -> promises
* code subscribes to be notified of changes and streams "push" data to these subscribers
* RxJS is functional -- functional operators are applied like for arrays
* streams are composable -- they are like a pipeline of operations over your data


=== Ways to get data into the application ===
<source lang="bash">
$ tsc
</source>


* AJAX HTTP Requests
If <code>tsc</code> is not directly available. It can also be run this way: <code>npm run tsc</code>.
* Websockets
* Indexdb
* LocalStorage
* Service Workers


=== New ideas on the horizon ===
If you want the server to watch for changes and compile on change (aka transpile) you can run the following command:


* MVW
<source lang="bash">
* Flux
$ npm run tsc:w
* Observables
</source>
* Falcor


== Forms ==
== turn off connection logging ==


=== FormBuilder ===
Setting logConnection to false in bs-config.json did not work. The connection is logged by a middleware called connect-logger and you can disable it by creating <span class="package">bs-config.js</span> with the following content.


<syntaxhighlight lang="typescript">
<source lang="js" highlight="2">
export class DemoFormSkuBuilder {
module.exports = {
   myForm: ControlGroup;
   server: { middleware: { 0: null }}
};
</source>


  constructor(fb: FormBuilder) {
== turn off file change updates ==
    this.myForm = fb.group({
      'sku': ['ABC123']
    });
  }


  onSubmit(value:string): void {
Add <span class="shell">logFileChanges</span> line to disable logging of file change updates.
    console.log('you submitted value: ',value);
  }
}
</syntaxhighlight>


=== @Component Annotation ===
<source lang="js" highlight="3">
module.exports = {
  server: { middleware: { 0: null }},
  logFileChanges: false
};
</source>


<source lang="typescript">
= Event =
import {Component} from 'angular2/core';
import {FORM_DIRECTIVES} from 'angular2/common';


@Component({
An example event binding.
  selector: 'demo-form-sku',
  directives: [FORM_DIRECTIVES], // a shorthand to several directives for forms
  template: `
<div class="ui raised segment">
    <h2 class="ui header">Demo Form: Sku</h2>
    <form #f="ngForm"
        (ngSubmit)="onSubmit(f.value)" // when I submit the form, call onSubmit on my component instance,
                                      // passing the value of the form as the arguments."
        classd="ui form">
        <div class="field">
            <label for="skuInput">SKU</label>
            <input type="text"
                id="skuInput"
                placeholder="SKU"
                ngControl="sku">
        </div>
        <button type="submit class="ui button">Submit</button>
    </form>
</div>
`
})


bootstrap(MyApp);
<source lang="ts">
<button (click)="onSave()">Save</button>
</source>
</source>


ngForm includes the <code>form</code> tag in its selector (instead of requiring you to explicitly add ngForm as an attribute). If you inject FORM_DIRECTIVES, ngForm will get automatically attached to any <form> tags you have in your view.
Canonical form:


=== ControlGroup ===
<source lang="ts">
 
<button on-click="onSave()">Save</button>
<syntaxhighlight lang="typescript">
</source>
let personInfo = new ControlGroup({
  firstName: new Control("Michael"),
  lastName: new Control("Han"),
  zip: new Control("90210")
})
 
// personInfo.value; .errors .dirty .valid
</syntaxhighlight>
 
=== Control ===
 
<syntaxhighlight lang="typescript">
let nameControl = new Control("Test");
 
let name = nameControl.value;
 
nameControl.errors; nameControl.dirty; nameControl.valid;
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<input type="text" ngControl="name"/>
</syntaxhighlight>
 
== Built-in Components ==
 
=== <nowiki>ngIf</nowiki> ===
 
<syntaxhighlight lang="html">
<div *ngIf="false"></div>
<div *ngIf="a > b"></div>
<div *ngIf="str == 'yes'"></div>
<div *ngIf="myFunc()"></div>
</syntaxhighlight>
 
=== <nowiki>ngSwitch</nowiki> ===
 
<syntaxhighlight lang="html">
<div class="container" [ngSwitch]="myVar">
  <div *ngSwitchWhen="'A'">Var is A</div>
  <div *ngSwitchWhen="'B'">Var is B</div>
  <div *ngSwitchDefault>Var is something else</div>
</div>
</syntaxhighlight>
 
=== <nowiki>ngStyle</nowiki> ===
 
<syntaxhighlight lang="html">
<div [style.background-color]="'yellow'">Testing</div>
 
<div [ngStyle]="{color: 'white', 'background-color': 'blue'}">testing</div>
 
<span [ngStyle]="{color: 'red'}" [style.font-size.px]="fontSize">red text</span>
</syntaxhighlight>
 
=== <nowiki>ngClass</nowiki> ===
 
<syntaxhighlight lang="css">
.bordered {
  border: 1px dashed black;
  background-color: #eee;
}
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div [ngClass]="{borderd: false}">This is never bordered</div>
<div [ngClass]="{borderd: true}">This is always bordered</div>
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div [ngClass]="{borderd: isBordered}">Using object literal. Border {{ isBordered ? "ON":"OFF" }}</div>
</syntaxhighlight>
 
----
 
<syntaxhighlight lang="typescript">
toggleBorder() {
  this.isBordered = !this.isBordered;
  this.classesObj = {
    bordered: this.isBordered
  };
}
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div [ngClass]="classesObj">Using object var. Border {{classesObj.bordered ? "ON":"OFF"}}</div>
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div class="base" [ngClass]="['blue','round']">This will always have a blue and round classes</div>
</syntaxhighlight>
 
<syntaxhighlight lang="typescript">
this.classList = ['blue','round'];
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div class="base" [ngClass]="classList"
</syntaxhighlight>
 
=== <nowiki>ngFor</nowiki> ===
 
<syntaxhighlight lang="typescript">
this.cities = ['Miami','Sao Paulo','New York'];
</syntaxhighlight>
 
<syntaxhighlight lang="html">
<div class="ui list" *ngFor="#c of cities">
  <div class="item">{{c}}</div>
</div>
</syntaxhighlight>
 
adding index
 
<syntaxhighlight lang="html">
<div class="ui list" *ngFor="#c of cities; #num = index">
  <div class="item">{{num+1}} - {{c}}</div>
</div>
</syntaxhighlight>
 
=== <nowiki>ngNonBindable</nowiki> ===
 
<syntaxhighlight lang="html">
<div>
  <span class="bordered">{{content}}</span>
  <span class="pre" ngNonBindable>
    &larr; This is what {{content}} rendered
  </span>
</div>
</syntaxhighlight>
 
== Miscellaneous ==
 
Four basic libraries to include
 
* es6-shim (for older browsers -- standardizes behaviors across browsers)
* angular2-polyfills (for standardizations, especially with zones, promises, and reflection)
* SystemJS (module loader)
* RxJS (enables reactive programming -- tools for Observables)
 
<syntaxhighlight lang="html">
<script src="node_modules/es6-shim/es6-shim.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<!-- main AngularJS 2 library -->
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
</syntaxhighlight>
 
TypeScript app.ts. import {bootstrap}, and {bootstrap} is called ''destructuring''.
 
<syntaxhighlight lang="javascript">
/// <reference path="node_modules/anguar2/ts/typings/node/node.d.ts"/>
/// <reference path="node_modules/anguar2/typings/browser.d.ts"/>
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
 
@Component({
    selector: 'hello-world',
    template: `
    <div>
    Hello world
    </div>
    `
})
 
class HelloWorld {
}
 
bootstrap(HelloWorld);
</syntaxhighlight>
 
Adding a variable. Adding a ''property'' is new to ES5: "name: string;". Double brackets <nowiki>{{</nowiki> are called "template-tags" (or "mustache tags"). Inside template-tags is ''expression''.
 
<syntaxhighlight lang="javascript">
/// <reference path="node_modules/anguar2/ts/typings/node/node.d.ts"/>
/// <reference path="node_modules/anguar2/typings/browser.d.ts"/>
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
 
@Component({
    selector: 'hello-world',
    template: `<div>Hello, {{name}}</div>`
})
 
class HelloWorld {
    name: string;
 
    constructor() {
        this.name = 'Felipe';
    }
}
 
bootstrap(HelloWorld);
</syntaxhighlight>
 
Array. *ngFor
 
<syntaxhighlight lang="javascript">
/// <reference path="node_modules/anguar2/ts/typings/node/node.d.ts"/>
/// <reference path="node_modules/anguar2/typings/browser.d.ts"/>
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
 
@Component({
    selector: 'hello-world',
    template: `
    <ul>
        <li *ngFor="#name of names">Hello {{name}}</li>
    </ul>
`
})
 
class HelloWorld {
    names: string[];
 
    constructor() {
        this.names = ['Ari', 'Carlos', 'Felipe', 'Nate'];
    }
}
 
bootstrap(HelloWorld);
</syntaxhighlight>
 
adding interaction.
 
<syntaxhighlight lang="javascript">
/// <reference path="node_modules/anguar2/ts/typings/node/node.d.ts"/>
/// <reference path="node_modules/anguar2/typings/browser.d.ts"/>
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
 
@Component({
    selector: 'trainer',
    template: `
<form class="ui large form segment">
    <h3 class="ui header">Add a Resource</h3>
 
    <div class="field">
        <label for="title">Title:</label>
        <input type="text" name="title" #newtitle>
    </div>
    <div class="field">
        <label for="link">Link:</label>
        <input type="url" name="link" #newlink>
    </div>
    <div class="field">
        <label for="credit">Credit:</label>
        <input type="number" name="credit" #newcredit>
    </div>
 
    <button (click)="addArticle(newtitle,newlink)" class="ui positive right floated button">Submit resource</button>
</form>
`
})
 
class TrainerApp {
    constructor() {
    }
 
    addResource(title: HTMLInputElement, link: HTMLInputElement): void {
        console.log(`Adding article title: ${title.value} and link: ${link.value}`);
    }
}
 
bootstrap(TrainerApp);
</syntaxhighlight>
 
<code><input name="title" #newtitle></code>
 
Tells Angular to ''bind'' this <input> to the variable '''newtitle'''. '''#newtitle''' syntax is called a ''resolve''.
 
----
 
Storing multiple items.
 
<syntaxhighlight lang="javascript">
/// <reference path="node_modules/angular2/ts/typings/node/node.d.ts"/>
/// <reference path="node_modules/angular2/typings/browser.d.ts"/>
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
 
class Resource {
    category: string;
    title: string;
    link: string;
    credit: number;
    votes: number;
 
    constructor(title: string, category: string, link: string, credit: number, votes?: number) {
        this.category = category;
        this.title = title;
        this.link = link;
        this.credit = credit;
        this.votes = votes || 0;
    }
 
    voteUp(): void {
        this.votes += 1;
    }
 
    voteDown(): void {
        this.votes -= 1;
    }
}
 
@Component({
    selector: 'trainer-item',
    inputs: ['resource'],
    host: {
        class: 'row'
    },
    template: `
<div class="four wide column center aligned votes">
    <div class="ui statistic">
        <div class="value">{{resource.votes}}</div>
        <div class="label"> Points</div>
    </div>
</div>
<div class="twelve wide column">
    <a class="ui large header" href="{{resource.link}}">{{resource.title}}</a>
    <ul class="ui big horizontal list voters">
        <li class="item">
            <a href (click)="voteUp()"><i class="arrow up icon"></i> upvote</a>
        </li>
        <li class="item">
            <a href (click)="voteDown()"><i class="arrow down icon"></i> downvote</a>
        </li>
    </ul>
</div>
`
})
 
class ResourceComponent {
    resource: Resource;
 
    voteUp(): boolean {
        this.resource.voteUp();
        return false;
    }
 
    voteDown(): boolean {
        this.resource.voteDown();
        return false;
    }
}
 
@Component({
    selector: 'trainer',
    directives: [ResourceComponent],
    template: `
<form class="ui large form segment">
    <h3 class="ui header">Add a Resource</h3>
 
    <div class="field">
        <label for="title">Title:</label>
        <input type="text" name="title" #newtitle>
    </div>
    <div class="field">
        <label for="category">Category:</label>
        <input type="text" name="category" #newcategory>
    </div>
    <div class="field">
        <label for="link">Link:</label>
        <input type="url" name="link" #newlink>
    </div>
    <div class="field">
        <label for="credit">Credit:</label>
        <input type="number" name="credit" #newcredit>
    </div>
 
    <button (click)="addResource(newtitle,newcategory,newlink,newcredit)" class="ui positive right floated button">Submit resource</button>
</form>
 
<div class="ui grid posts">
    <trainer-item *ngFor="#resource of resources" [resource]="resource"></trainer-item>
</div>
`
})
 
class TrainerApp {
    resources: Resource[];
 
    constructor() {
        this.resources = [
            new Resource('Chapter 1','Angular 2','http://angular.io',3,10),
            new Resource('Chapter 2','Angular 2','http://angular.io',3,10),
            new Resource('Chapter 3','Angular 2','http://angular.io',3,10),
        ];
    }
 
    addResource(title: HTMLInputElement, category: HTMLInputElement, link: HTMLInputElement, credit: HTMLInputElement): void {
        console.log(`Adding resource -- title: ${title.value}, category: ${category.value}, link: ${link.value}, credit: ${credit.value}`);
    }
}
 
bootstrap(TrainerApp);
</syntaxhighlight>
 
----
 
Add sorting functionality.
 
<syntaxhighlight lang="javascript">
({
`
...
<div class="ui grid posts">
    <trainer-item *ngFor="#res_item of sortedResources()" [resource]="res_item"></trainer-item>
</div>
`
})
 
class TrainerApp {
    resources: Resource[];
 
    constructor() {
        this.resources = [
            new Resource('Chapter 1','Angular 2','http://angular.io','3',10),
            new Resource('Chapter 2','Angular 2','http://angular.io','3',10),
            new Resource('Chapter 3','Angular 2','http://angular.io','3',10),
        ];
    }
 
    addResource(title: HTMLInputElement, category: HTMLInputElement, link: HTMLInputElement, credit: HTMLInputElement): void {
        console.log(`Adding resource -- title: ${title.value}, category: ${category.value}, link: ${link.value}, credit: ${credit.value}`);
        this.resources.push(new Resource(title.value,category.value,link.value,credit.value));
        title.value = category.value = link.value = credit.value = '';
    }
 
    sortedResources(): Resource[] {
        return this.resources.sort((a: Resource, b: Resource) => b.credit - a.credit);
    }
}
</syntaxhighlight>
 
Advantages of TypeScript over ES5:
 
* types
* classes
* annotations
* imports
* language utilities (e.g. destructuring)
 
<syntaxhighlight lang="javascript">
</syntaxhighlight>
 
@Component is called a ''decorator'', which adds metadata to the class that follows it.
 
Using the {{ ... }} syntax is called ''template binding''.
 
''directives'' specifies other components we want to be able to use in this view. The option takes an array of classes.


<nowiki>[squareBrackets]</nowiki> pass inputs and (parenthesis) handle outputs.
[https://developer.mozilla.org/en-US/docs/Web/Events List of events that can be used on MDN.]

Latest revision as of 13:52, 8 July 2016

Angular 2 by Examples

Running the app (via npm)

Compile just once. This executable binary is founder under ./npm_modules/.bin/ folder.

$ tsc

If tsc is not directly available. It can also be run this way: npm run tsc.

If you want the server to watch for changes and compile on change (aka transpile) you can run the following command:

$ npm run tsc:w

turn off connection logging

Setting logConnection to false in bs-config.json did not work. The connection is logged by a middleware called connect-logger and you can disable it by creating bs-config.js with the following content.

module.exports = {
  server: { middleware: { 0: null }}
};

turn off file change updates

Add logFileChanges line to disable logging of file change updates.

module.exports = {
  server: { middleware: { 0: null }},
  logFileChanges: false
};

Event

An example event binding.

<button (click)="onSave()">Save</button>

Canonical form:

<button on-click="onSave()">Save</button>

List of events that can be used on MDN.