|
|
(7 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
| == npm lite-server related ==
| | [[Angular 2 by Examples]] |
|
| |
|
| === turn off connection logging === | | = Running the app (via npm) = |
|
| |
|
| 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.json</span> with the following content.
| | Compile just once. This executable binary is founder under <span class="shell">./npm_modules/.bin/</span> folder. |
|
| |
|
| <source lang="json"> | | <source lang="bash"> |
| {
| | $ tsc |
| "middleware": {
| |
| "0": null
| |
| }
| |
| }
| |
| </source> | | </source> |
|
| |
|
| == Event ==
| | If <code>tsc</code> is not directly available. It can also be run this way: <code>npm run tsc</code>. |
|
| |
|
| An example event binding.
| | If you want the server to watch for changes and compile on change (aka transpile) you can run the following command: |
|
| |
|
| <source lang="typescript"> | | <source lang="bash"> |
| <button (click)="onSave()">Save</button>
| | $ npm run tsc:w |
| </source> | | </source> |
|
| |
|
| Canonical form:
| | == 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 <span class="package">bs-config.js</span> with the following content. |
|
| |
|
| <source lang="typescript"> | | <source lang="js" highlight="2"> |
| <button on-click="onSave()">Save</button>
| | module.exports = { |
| | server: { middleware: { 0: null }} |
| | }; |
| </source> | | </source> |
|
| |
|
| [https://developer.mozilla.org/en-US/docs/Web/Events List of events that can be used on MDN.]
| | == turn off file change updates == |
|
| |
|
| == Data Architecture == | | Add <span class="shell">logFileChanges</span> line to disable logging of file change updates. |
|
| |
|
| === Observables (aka Reactive Programming) === | | <source lang="js" highlight="3"> |
| | module.exports = { |
| | server: { middleware: { 0: null }}, |
| | logFileChanges: false |
| | }; |
| | </source> |
|
| |
|
| * Promises emit single values, and streams emit multiple values
| | = Event = |
| ** 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 ===
| | An example event binding. |
|
| |
|
| * AJAX HTTP Requests
| | <source lang="ts"> |
| * Websockets
| | <button (click)="onSave()">Save</button> |
| * Indexdb
| | </source> |
| * LocalStorage
| |
| * Service Workers
| |
|
| |
|
| === New ideas on the horizon ===
| | Canonical form: |
|
| |
|
| * MVW
| | <source lang="ts"> |
| * Flux
| | <button on-click="onSave()">Save</button> |
| * Observables
| |
| * Falcor
| |
| | |
| == Forms ==
| |
| | |
| === FormBuilder ===
| |
| | |
| <syntaxhighlight lang="typescript"> | |
| export class DemoFormSkuBuilder {
| |
| myForm: ControlGroup;
| |
| | |
| constructor(fb: FormBuilder) {
| |
| this.myForm = fb.group({
| |
| 'sku': ['ABC123']
| |
| });
| |
| }
| |
| | |
| onSubmit(value:string): void {
| |
| console.log('you submitted value: ',value);
| |
| }
| |
| }
| |
| </syntaxhighlight> | |
| | |
| === @Component Annotation ===
| |
| | |
| <source lang="typescript">
| |
| import {Component} from 'angular2/core';
| |
| import {FORM_DIRECTIVES} from 'angular2/common';
| |
| | |
| @Component({
| |
| 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> | | </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.
| | [https://developer.mozilla.org/en-US/docs/Web/Events List of events that can be used on MDN.] |
| | |
| === ControlGroup ===
| |
| | |
| <syntaxhighlight lang="typescript">
| |
| 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>
| |
| ← 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.
| |