(docs) getting started evolved with some unit-tests for quickstart

This commit is contained in:
Ward Bell 2015-09-09 14:20:43 -07:00 committed by Naomi Black
parent 50e758ba60
commit c44e966278
47 changed files with 645 additions and 317 deletions

4
.gitignore vendored
View File

@ -1,4 +1,8 @@
node_modules
bower_components
jspm_packages
typings
*.map
www
.DS_Store
.idea

View File

@ -0,0 +1 @@
src/**/*.js

View File

@ -0,0 +1,10 @@
#Getting Started (TS) for the DevGuide developer
This is the source code for the "Getting Started" Typescrip example code.
There are files here that are *for the audience* and **not to be executed during example development**!
* **package.json** - as the audience will see it; the example reaches up to the site level **node_modules**
and the scripts are not supposed to work here.
* **tsd.json** - as the audience will see it; the example reaches up to the example level typings

View File

@ -1,37 +0,0 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
// #docregion
// #docregion import
var angular2_1 = require('angular2/angular2');
// #enddocregion
// #docregion class-w-annotations
var AppComponent = (function () {
function AppComponent() {
}
AppComponent = __decorate([
angular2_1.Component({
selector: 'my-app'
}),
angular2_1.View({
template: '<h1 id="output">My First Angular 2 App</h1>'
}),
__metadata('design:paramtypes', [])
], AppComponent);
return AppComponent;
})();
// #enddocregion
// #enddocregion
// #docregion bootstrap
angular2_1.bootstrap(AppComponent);
// #enddocregion
// #enddocregion
//# sourceMappingURL=app.js.map

View File

@ -1,15 +0,0 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>
System.import('app');
</script>
</body>
</html>

View File

@ -0,0 +1,15 @@
{
"name": "ng2-getting-started",
"version": "0.0.1",
"dependencies": {
"angular2": "2.0.0-alpha.35",
"es6-module-loader": "^0.16",
"systemjs": "^0.16",
"traceur": "0.0.91"
},
"scripts": {
"postinstall": "cd src && tsd reinstall -r -o && cd ..",
"tsc": "tsc -p src -w",
"start": "live-server --open=src"
}
}

View File

@ -0,0 +1,16 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<script src="../node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="../node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>
System.import('app');
</script>
</body>
</html>

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}

View File

@ -0,0 +1,24 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"angular2/angular2.d.ts": {
"commit": "cd2e71bb1f0459197e733be66fdeafaec600514d"
},
"es6-promise/es6-promise.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"jasmine/jasmine.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx-lite.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
}
}
}

View File

@ -0,0 +1 @@
src/**/*.js

View File

@ -1,34 +0,0 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
// #docregion
// #docregion import
var angular2_1 = require('angular2/angular2');
// #enddocregion
var MyAppComponent = (function () {
function MyAppComponent() {
this.name = 'Alice';
}
MyAppComponent = __decorate([
angular2_1.Component({
selector: 'my-app'
}),
angular2_1.View({
template: '<h1 id="output">Hello {{ name }}</h1>'
}),
__metadata('design:paramtypes', [])
], MyAppComponent);
return MyAppComponent;
})();
// #docregion bootstrap
angular2_1.bootstrap(MyAppComponent);
// #enddocregion
//# sourceMappingURL=app.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"app.js","sourceRoot":"","sources":["app.ts"],"names":["MyAppComponent","MyAppComponent.constructor"],"mappings":";;;;;;;;;;;AAEA,AAFA,aAAa;AACb,oBAAoB;AACpB,yBAAyC,mBAAmB,CAAC,CAAA;AAG7D,AAFA,gBAAgB;;IAWfA;QACCC,IAAIA,CAACA,IAAIA,GAAGA,OAAOA,CAACA;IACrBA,CAACA;IAXFD;QAACA,oBAASA,CAACA;YACVA,QAAQA,EAAEA,QAAQA;SAClBA,CAACA;QACDA,eAAIA,CAACA;YACLA,QAAQA,EAAEA,uCAAuCA;SACjDA,CAACA;;uBAODA;IAADA,qBAACA;AAADA,CAACA,AAZD,IAYC;AAGD,AADA,uBAAuB;AACvB,oBAAS,CAAC,cAAc,CAAC,CAAC;AAC1B,gBAAgB"}

View File

@ -3,13 +3,14 @@
<head>
<!-- #docregion head -->
<title>Angular 2 Quickstart</title>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
<script src="node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<!-- #enddocregion -->
</head>
<body>
<my-app></my-app>
<script>System.import('app');</script>
<app></app>
<script>System.import('src/app');</script>
</body>
</html>

View File

@ -0,0 +1,21 @@
{
"name": "ng2-quickstart",
"version": "0.0.1",
"license": "ICS",
"repository": {},
"dependencies": {
"angular2": "2.0.0-alpha.35",
"es6-module-loader": "^0.16",
"systemjs": "^0.16",
"traceur": "0.0.91"
},
"devDependencies": {
"jasmine-core": "^2.3.4",
"zone.js": "^0.5.3"
},
"scripts": {
"postinstall": "cd src && tsd reinstall -r -o && cd ..",
"tsc": "tsc -p src -w",
"start": "live-server"
}
}

View File

@ -0,0 +1,68 @@
///// Boiler Plate ////
import {bind} from 'angular2/angular2';
import {
beforeEachBindings, DebugElement, RootTestComponent as RTC,
// Jasmine overrides
beforeEach, ddescribe, xdescribe, describe, iit, it, xit, //expect,
AsyncTestCompleter, inject, RootTestComponent, TestComponentBuilder,
} from 'angular2/test';
//// Testing this component ////
import {AppComponent} from './app';
describe('AppComponent', () => {
describe('(no DOM)', () => {
it('component has name == "Alice"', () => {
let app = new AppComponent;
expect(app.name).toEqual('Alice');
});
});
describe('(in DOM)', () => {
it('component has name == "Alice"', injectTcb((tcb, done) => {
tcb
.createAsync(AppComponent)
.then((rootTC:RTC) => {
let ac:AppComponent = rootTC.componentInstance;
expect(ac.name).toEqual('Alice');
})
.catch(fail).then(done,done);
}));
it('DOM has name == "Alice"', injectTcb((tcb, done) => {
tcb
.createAsync(AppComponent)
.then((rootTC:RTC) => {
rootTC.detectChanges();
let domName = rootTC.componentViewChildren[0].nativeElement.innerHTML;
expect(domName).toMatch('Alice');
})
.catch(fail).then(done,done);
}));
//rootTC.nativeElement.getElementsByTagName('h1')[0].innerHTML
it('DOM has name == "Alice" (2)', injectTcb((tcb, done) => {
tcb
.createAsync(AppComponent)
.then((rootTC:RTC) => {
rootTC.detectChanges();
let domName = rootTC.nativeElement
// jQuery goes here
.getElementsByTagName('h1')[0].innerHTML;
expect(domName).toMatch('Alice');
})
.catch(fail).then(done,done);
}));
});
});
///////// test.helpers.ts: here for now ////////
function injectTcb(testFn: (tcb: TestComponentBuilder, done: ()=>void) => void) {
return inject([TestComponentBuilder, AsyncTestCompleter], function injectWrapper(tcb: TestComponentBuilder, async: AsyncTestCompleter) {
testFn(tcb, async.done.bind(async));
});
}

View File

@ -4,12 +4,12 @@ import {Component, View, bootstrap} from 'angular2/angular2';
// #enddocregion
@Component({
selector: 'my-app'
selector: 'app'
})
@View({
template: '<h1 id="output">Hello {{ name }}</h1>'
})
class MyAppComponent {
export class AppComponent {
name : string;
constructor() {
@ -18,5 +18,5 @@ class MyAppComponent {
}
// #docregion bootstrap
bootstrap(MyAppComponent);
bootstrap(AppComponent);
// #enddocregion

View File

@ -0,0 +1,9 @@
describe("Jasmine sample test", function() {
it("1+1 should be 2", function() {
var result = 1 + 1;
expect(result).toBe(2);
});
});

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}

View File

@ -0,0 +1,24 @@
{
"version": "v4",
"repo": "borisyankov/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"angular2/angular2.d.ts": {
"commit": "cd2e71bb1f0459197e733be66fdeafaec600514d"
},
"es6-promise/es6-promise.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"jasmine/jasmine.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx-lite.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
}
}
}

View File

@ -0,0 +1,55 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>QuickStart Tests</title>
<link rel="stylesheet" href="node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.src.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
<script src="node_modules/angular2/bundles/test_lib.dev.js"></script>
<script src="node_modules/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="node_modules/zone.js/dist/jasmine-patch.js"></script>
</head>
<body>
<app><!--placeholder--></app>
<script>
(function() {
Error.stackTraceLimit=Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;
var imports = [
'src/dummy.spec',
'src/app.spec',
'@empty' // placeholder makes it easier to comment-out specs above
].map(System.import.bind(System));
Promise.all(imports)
.then( function() {
// Must designate a BrowserDomAdapter or else DOM testing bombs
// (e.g. when testing component and call `tcb.createAsync`) for lack of `DOM` object
// Igor's recommended approach based on
// https://github.com/angular/angular/blob/master/test-main.js
//
// TODO: BrowserDomAdapter should be exposed through 'angular2/test' instead
var DomAdapterModule = System.get('angular2/src/dom/browser_adapter');
if (DomAdapterModule) {
DomAdapterModule.BrowserDomAdapter.makeCurrent();
}
})
.then( function() { window.onload();} ) // re-execute Jasmine's buildup
.catch( function(err) { console.log(err);} );
})();
</script>
</body>
</html>

View File

@ -1,9 +1,9 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}

View File

@ -5,20 +5,20 @@
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"angular2/angular2.d.ts": {
"commit": "cd2e71bb1f0459197e733be66fdeafaec600514d"
},
"es6-promise/es6-promise.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"jasmine/jasmine.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"rx/rx-lite.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"angular2/angular2.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
},
"jasmine/jasmine.d.ts": {
"commit": "71d072b7354936b88d57c2029042d2da7c6ec0e7"
}
}
}

View File

@ -1,17 +0,0 @@
```
<!DOCTYPE html>
<html>
<head>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>
System.import('app');
</script>
</body>
</html>
```

View File

@ -0,0 +1,18 @@
```
<!DOCTYPE html>
<html>
<head>
<script src="../node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="../node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>
System.import('app');
</script>
</body>
</html>
```

View File

@ -1,3 +0,0 @@
```
angular2_1.bootstrap(MyAppComponent);
```

View File

@ -1,3 +0,0 @@
```
bootstrap(MyAppComponent);
```

View File

@ -1,3 +0,0 @@
```
var angular2_1 = require('angular2/angular2');
```

View File

@ -1,20 +0,0 @@
```
var angular2_1 = require('angular2/angular2');
var MyAppComponent = (function () {
function MyAppComponent() {
this.name = 'Alice';
}
MyAppComponent = __decorate([
angular2_1.Component({
selector: 'my-app'
}),
angular2_1.View({
template: '<h1 id="output">Hello {{ name }}</h1>'
}),
__metadata('design:paramtypes', [])
], MyAppComponent);
return MyAppComponent;
})();
angular2_1.bootstrap(MyAppComponent);
//# sourceMappingURL=app.js.map
```

View File

@ -1,6 +1,7 @@
```
<title>Angular 2 Quickstart</title>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
<script src="node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
```

View File

@ -2,13 +2,14 @@
<html>
<head>
<title>Angular 2 Quickstart</title>
<script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
<script src="node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
</head>
<body>
<my-app></my-app>
<script>System.import('app');</script>
<app></app>
<script>System.import('src/app');</script>
</body>
</html>
```

View File

@ -0,0 +1,3 @@
```
bootstrap(AppComponent);
```

View File

@ -2,12 +2,12 @@
import {Component, View, bootstrap} from 'angular2/angular2';
@Component({
selector: 'my-app'
selector: 'app'
})
@View({
template: '<h1 id="output">Hello {{ name }}</h1>'
})
class MyAppComponent {
export class AppComponent {
name : string;
constructor() {
@ -15,6 +15,6 @@ class MyAppComponent {
}
}
bootstrap(MyAppComponent);
bootstrap(AppComponent);
```

View File

@ -0,0 +1,56 @@
```
<!DOCTYPE html>
<html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>QuickStart Tests</title>
<link rel="stylesheet" href="node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="node_modules/traceur/bin/traceur-runtime.js"></script>
<script src="node_modules/es6-module-loader/dist/es6-module-loader.src.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
<script src="node_modules/angular2/bundles/test_lib.dev.js"></script>
<script src="node_modules/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="node_modules/zone.js/dist/jasmine-patch.js"></script>
</head>
<body>
<app><!--placeholder--></app>
<script>
(function() {
Error.stackTraceLimit=Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;
var imports = [
'src/dummy.spec',
'src/app.spec',
'@empty' // placeholder makes it easier to comment-out specs above
].map(System.import.bind(System));
Promise.all(imports)
.then( function() {
// Must designate a BrowserDomAdapter or else DOM testing bombs
// (e.g. when testing component and call `tcb.createAsync`) for lack of `DOM` object
// Igor's recommended approach based on
// https://github.com/angular/angular/blob/master/test-main.js
//
// TODO: BrowserDomAdapter should be exposed through 'angular2/test' instead
var DomAdapterModule = System.get('angular2/src/dom/browser_adapter');
if (DomAdapterModule) {
DomAdapterModule.BrowserDomAdapter.makeCurrent();
}
})
.then( function() { window.onload();} ) // re-execute Jasmine's buildup
.catch( function(err) { console.log(err);} );
})();
</script>
</body>
</html>
```

View File

@ -1,130 +1,200 @@
include ../_util-fns
include ../../../../_includes/_util-fns
:markdown
Let's start from zero and build a simple Angular 2 application in JavaScript.
.callout.is-helpful
header Don't want JavaScript?
:markdown
Although we're getting started in JavaScript, you can also write Angular 2 apps
in TypeScript and Dart by selecting either of those languages from the combo-box in the banner.
:markdown
We'll do it in four short steps
1. Create a new project folder and an *index.html*
1. Write the root component for our application in *app.js*
1. Bootstrap the app
1. Run it
.l-main-section
:markdown
## Install Angular2
There are four steps to create any Angular app:
## Create a project folder and an *index.html*
1. Create an entry point HTML file where users will start
1. Load the Angular library at the top of the file
1. Make a root component for your application
1. Bootstrap Angular
You can edit and test out your apps by serving local files with a web server. Follow the steps in the <a href="../quickstart.html">quickstart</a> to get Typescript setup.
If you don't already have an HTTP server, you can install one using <code>npm install -g http-server</code>. (If that results in an access error, then you might need to use <code><b>sudo</b> npm ...</code>.)
For example:
Create a new folder to hold our application project, perhaps like this:
pre.prettyprint.lang-bash
code.
# From the directory that contains index.html:
npm install -g http-server # Or sudo npm install -g http-server
http-server # Creates a server at localhost:8080
# In a browser, visit localhost:8080/index.html
code mkdir firstNgApp && cd firstNgApp
.callout.is-helpful
header Typescript vs ES5
:markdown
Although we work through the examples in TypeScript, you can also use
regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript
version. Note that in ES5, you'd want to name your files `.js` rather than
`.ts`.
Then add a new `index.html` file to the project folder and enter the following HTML
.l-main-section
:markdown
## Create an entry point
Create an `index.html` file and add the Angular library tags and a `main.ts` file where
you'll build your first component.
+makeExample('gettingstarted', 'js/index.html', 'index.html')(format="")
In the `<body>`, add an element called `<my-app>` that will be the root of your
application.
The TypeScript setup includes System.js, a third-party open-source library that adds ES6 module loading functionality to browsers. This step isn't needed for the ES5 version.
- var tsStyles = { pnk: [ /script (src=.*quot)/g, /System\.(import)/g] }
- var jsStyles = { otl: /script src=(&quot.*&quot)/g }
+makeTabs('gettingstarted', 'ts/index.html,js/index.html', 'TypeScript, JavaScript', [ tsStyles, jsStyles ])
.callout.is-helpful
header Don't use code.angularjs.org in a live app
:markdown
This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is
fine for examples, but you'd want to serve it yourself or use a CDN for real deployment.
.l-main-section
:markdown
## Set up the starting component
In `main.ts`, create a class called `AppComponent`, configure it to bind to the
`<my-app>` element in `index.html`, and call Angular's `bootstrap()` to kick
it all off like this:
+makeTabs("gettingstarted", "ts/main.ts, js/main.js", "TypeScript, JavaScript",
{ otl: [ /(AppComponent)/g, /(my-app)/g ],
pnk: / (\w*:)/g } )
.callout.is-helpful
header Annotations vs Decorators
.l-sub-section
:markdown
If you are transpiling using a tool that translates the `@` symbols to
annotations (for example Traceur), you will need to import the annotation versions of
Component and View. That can be easily achieved using
`import {ComponentAnnotation as Component, ViewAnnotation as View}`.
Our app loads two script files in the `<head>` element:
>***angular.js***, the Angular 2 library.
>***app.js***, the application JavaScript which we're about to write.
In the `<body>`, there's an element called `<my-app>`. This is a placeholder for the *root* of our
application. Angular will display our application content here.
.l-main-section
:markdown
## Write the *app* component
Create an *app.js* file with the following content:
+makeExample('gettingstarted', 'js/app-class-w-annotations.js')
:markdown
When we step back and squint, we see that
we're creating a visual component named **`appComponent`** by chaining three methods
originating in the global Angular namespace object called, **`ng`**.
```
var appComponent = ng
.Component({...})
.View({...})
.Class({...})
```
The **`Component`** method tells Angular that this is a component
controlling the element named "my-app".
+makeExample('gettingstarted', 'js/app-component.js')
:markdown
You may remember we added such an element to our *index.html* above.
The **`View`** method identifies the HTML template
that defines the visual appearance of the component.
+makeExample('gettingstarted', 'js/app-view.js')
:markdown
We're writing the HTML template inline
in this example. Later we'll move the HTML to a view template file and
assign the template's filename to the `templateUrl`.
We'll prefer that practice for all but the most trivial templates.
The **`Class`** method is where we implement the component itself,
giving it properties and methods that bind to the view and whatever
behavior is appropriate for this part of the UI.
+makeExample('gettingstarted', 'js/app-class.js')
:markdown
This component has the minimum implementation:
a *no-op* constructor function that does nothing because there is nothing to do.
We'll see more interesting component classes in future examples.
.l-main-section
:markdown
## Run it!
Open `index.html` through your web server and you should see:
We need a file server to serve the static assets of our application (*index.html* and *app.js*).
If you have python on your machine, you're in luck: python ships with a basic static file server.
Open a terminal window and enter:
pre.prettyprint.lang-bash
code python -m SimpleHTTPServer 8000
:markdown
then point a browser to http://localhost:8000 which should display our simple text message:
figure.image-display
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
:markdown
**If you don't have python**, you may have to install a server.
You might prefer one of the many node-based static servers such as
[http-server](https:/github.com/nodeapps/http-server "http-server"),
[superstatic](https://www.npmjs.com/package/superstatic "superstatic"), or
[live-server](https://www.npmjs.com/package/live-server "live-server").
:markdown
For this example we'll use **live-server** because it performs a live reload by default and it's
fun to watch the browser update as we make changes.
Open a terminal (or Windows/Linux command line) and enter:
pre.prettyprint.lang-bash
code npm install -g live-server
.callout.is-helpful
:markdown
Install [**node** and **npm**](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
first if you haven't already. They're indispensible front-end developer tools.
:markdown
After it finishes installing, start the server on port 8000
pre.prettyprint.lang-bash
code live-server --port=8000
:markdown
**live-server** loads the browser for us and refreshes the page as we make
changes to the application.
.l-main-section
:markdown
## Explanations
## Add TypeScript Type Definition Files (optional)
This basic Angular app contains the structure for any app you'll build.
"*Wait*", you say, "*we're writing in JavaScript, not TypeScript!*".
Indeed we are. But code editors (such as [Visual Studio Code](https://code.visualstudio.com/) and
[Web Storm](https://www.jetbrains.com/webstorm/features/))
can improve the JavaScript development experience by providing type information and
displaying API documentation ("intellisense") based on TypeScript type definition files.
.l-sub-section
:markdown
### It's all a tree
We can download type definitions files for third-party libraries such as Angular
from the [DefinitelyTyped](http://definitelytyped.org/) repository using the
[**tsd package manager**](https://www.npmjs.com/package/tsd "TSD Package Manager").
You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top
level container for the rest of your application. You've named this one `AppComponent`, but there's
nothing special about the name and you can use whatever makes sense to you.
If you haven't already installed the *tsd*, do it now
with an npm command entered in a terminal or command window.
The root component's job is to give a location in the `index.html` file where your application will
render through its element, in this case `<my-app>`. There is also nothing special about this
element name; you can pick it as you like.
pre.prettyprint.lang-bash
code npm install -g tsd
The root component loads the initial template for the application that will load other components to perform
whatever functions your application needs - menu bars, views, forms, etc. We'll walk through examples of all of
these in the following pages.
:markdown
Now let's download and install the core set of type definitions files for Angular development
in the root directory of our application.
.l-sub-section
:markdown
### @Component and @View annotations
pre.prettyprint.lang-bash
code tsd query angular2 es6-promise rx rx-lite jasmine --action install --save
A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`).
:markdown
We'll find a ***typings*** folder in the root directory
with subfolders for each of the five downloaded type definition files (angular, es6-promise, rx, rx-lite, jasmine).
Type definition files have names ending in ***d.ts***.
There's also a summary ***tsd.d.ts*** file containing references to each of them.
The `@Component` annotation defines the HTML tag for the component by specifying the component's CSS selector.
Check your editor's documentation for instructions on using the *tsd.d.ts* file to
light up type checking and intellisense for these libraries.
The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file.
.l-main-section
:markdown
## It's all a tree
.l-sub-section
:markdown
### import vs. window.angular
We can think of Angular apps as a tree of components.
The main difference between the ES5 and TypeScript versions is the loading of modules.
The `AppComponent` that we've been talking about acts as the top
level container - the root of the tree - for the rest of our application.
There's nothing special about the `AppComponent` name and we can use whatever makes sense to us.
**TypeScript**<br/>
TypeScript supports ES6 module loading syntax. ES6 modules allow for modular loading of JavaScript code. Using ES6 modules you can cherry-pick only what you need for your app.
We've pinned the root component to an element in the `index.html` file where our application will
render its view. The element is called `<my-app>` but there is nothing special about this
name either.
**Javascript**<br/>
In ES5 the script file creates an angular property on the window of the browser. This property contains every piece of Angular core, whether you need it or not.
The *root component* loads the initial template for the application.
That template could load other components such as menu bars, views, and forms
that display information and respond to user gestures.
+makeTabs('gettingstarted', 'ts/main-import.ts', 'TypeScript')
And these components could load yet more components until the browser page became a deep tree
of nested functionality.
+makeExample('gettingstarted/js', 'main-bootstrap.js', 'JavaScript')
We'll walk through examples of these scenarios in the following pages.

View File

@ -10,9 +10,11 @@ include ../../../../_includes/_util-fns
in JavaScript and Dart by selecting either of those languages from the combo-box in the banner.
:markdown
We'll do it in seven short steps
We'll do it in short steps
1. Install the prerequisites for Angular TypeScript development
1. Create a new project folder and configure TypeScript
1. Create an application folder
1. Install the npm packages our app needs
1. Prepare for TypeScript compilation
1. Create an *index.html*
1. Write the root component for our application in *app.ts*
1. Bootstrap the app
@ -41,18 +43,7 @@ include ../../../../_includes/_util-fns
code npm install -g tsd
:markdown
Install a node **static server** to serve the static files of our application.
.alert.is-helpful
:markdown
You can skip this step if you've got python on your machine because python ships with a static server.
Or you can install one of the many node-based static servers such as
[http-server](https:/github.com/nodeapps/http-server "http-server"),
[superstatic](https://www.npmjs.com/package/superstatic "superstatic"), or
[live-server](https://www.npmjs.com/package/live-server "live-server").
:markdown
Install a node **static server** to serve our application.
We'll use **live-server** for this example because it performs a live reload by default and it's
fun to watch the browser update as we make changes.
@ -61,7 +52,7 @@ include ../../../../_includes/_util-fns
.l-main-section
:markdown
## Create a project folder and configure TypeScript
## Create the application folder
Create a new folder to hold our application project, perhaps like this:
@ -69,60 +60,110 @@ include ../../../../_includes/_util-fns
code mkdir firstNgApp && cd firstNgApp
:markdown
We'll refer to this as our application's **root folder**.
.l-main-section
:markdown
## Install npm packages
Our application will need some 3rd party JavaScript files:
>***angular.js***, the Angular 2 library.
>***es6-module-loader***, a "shim" that enables today's browsers load files
using the latest "ES6" JavaScript syntax.
>***system.js***, a third-party open-source library that adds module loading functionality to our browser.
>***traceur-runtime.js*** to transpile the TypeScript-generated JavaScript into the version of Javascript
our browser understands (the version known as "ES5").
For our little "GettingStarted" app, we could just install these packages
with four npm commands.
In our real apps, we'd take an extra minute to create a *package.json* configuration file.
This is a more robust, less error-prone approach, that we can maintain as our application evolves.
Create this **package.json** file in the root folder:
```
{
"name": "getting-started",
"version": "0.0.1",
"dependencies": {
"angular2": "2.0.0-alpha.35",
"es6-module-loader": "^0.16",
"systemjs": "^0.16",
"traceur": "0.0.91"
}
}
```
Now we install our script packages with one command
pre.prettyprint.lang-bash
code npm install
.l-main-section
:markdown
## Prepare for TypeScript Compilation
We're done at the root level of our application.
We'll build the rest of the application in a subfolder called *src*.
Let's make that folder and go there.
pre.prettyprint.lang-bash
code mkdir src && cd src
:markdown
We have one last preparation step before we start coding.
We prefer writing TypeScript apps in an editor that understands TypeScript,
an editor such as [Visual Studio Code](https://code.visualstudio.com/) or
[Web Storm](https://www.jetbrains.com/webstorm/features/).
We should tell that editor how to compile TypeScript to JavaScript
with a configuration file named **tsconfig.json**.
We need to tell that editor how to interpret our TypeScript
which we do with a configuration file named **tsconfig.json**.
This configuration file also simplifies the TypeScript compilation command we'll run later in this story.
Create *tsconfig.json* now with the following JSON content:
```json
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
```
.l-main-section
:markdown
## Create an *index.html*
Add a new `index.html` file to the project folder and enter the following HTML
+makeExample('gettingstarted', 'ts/index.html', 'index.html')
+makeExample('gettingstarted', 'ts/src/index.html', 'index.html')
.l-sub-section
:markdown
Our app loads three script files in the `<head>` element:
Notice in the `<head>` element that we're loading the scripts we installed earlier with npm.
>***traceur-runtime.js*** to transpile the TypeScript-generated JavaScript into the version of Javascript
our browser understands (the version known as "ES5").
>***system.js***, a third-party open-source library that adds module loading functionality to our browser.
>***angular.js***, the Angular 2 library.
In the `<body>`, there's an element called `<my-app>`. This is a placeholder for the *root* of our
There's an element called `<app>` in the `<body>`. This is a placeholder for the *root* of our
application. Angular will display our application content here.
The final inline script tells *system.js* to load another JavaScript file named "app".
We haven't written that file yet; let's do so now.
.l-main-section
:markdown
## Write the *app* component
Create an *app.ts* file and add an empty class called `AppComponent` as follows:
+makeExample('gettingstarted', 'ts/app-class.ts')
+makeExample('gettingstarted', 'ts/src/app-class.ts')
:markdown
We won't ask this class to do anything. It's just an empty, meaningless class until we tell
@ -130,13 +171,13 @@ include ../../../../_includes/_util-fns
We import the `component` and `view` *annotations* that we need from the Angular library at the top of the file:
+makeExample('gettingstarted', 'ts/app-import.ts')
+makeExample('gettingstarted', 'ts/src/app-import.ts')
:markdown
Then we apply those annotations to the `AppComponent` class by writing the following lines
just above the class definition:
+makeExample('gettingstarted', 'ts/app-class-w-annotations.ts')
+makeExample('gettingstarted', 'ts/src/app-class-w-annotations.ts')
.l-sub-section
:markdown
@ -160,12 +201,12 @@ include ../../../../_includes/_util-fns
with an instance of the `AppComponent` class as the root component.
We call this "bootstrapping the app".
+makeExample('gettingstarted', 'ts/app-bootstrap.ts')
+makeExample('gettingstarted', 'ts/src/app-bootstrap.ts')
:markdown
Here is the complete *app.ts*
+makeExample('gettingstarted', 'ts/app.ts', 'app.ts')
+makeExample('gettingstarted', 'ts/src/app.ts', 'app.ts')
.l-main-section
@ -175,43 +216,47 @@ include ../../../../_includes/_util-fns
We've written our app in TypeScript but the browser only understands JavaScript.
We must run the TypeScript compiler to produce JavaScript for the browser.
Open a terminal window in the root of the code director and enter:
Open a terminal window in the **root of the application folder** (not *src*) and enter:
pre.prettyprint.lang-bash
code tsc
code tsc -p src -w
:markdown
After it runs we should find the generated *app.js* file in the project folder and also an *app.map.js* file that
After it runs we should find the generated *app.js* file in the *src* folder and also an *app.map.js* file that
helps debuggers navigate between the JavaScript and the TypeScript source.
We gave *tsc* the watch option (`-w`). It will watch for changes to our *.ts* files and
recompile them automatically. Leave it running in this terminal window.
.l-main-section
:markdown
## Run it!
Now we can see this app in action by serving the files we created with a local web server.
Now we are ready to see this app in action.
Open a another terminal window in the root of the code directory and launch the server.
If we have python installed on our machine, we can run a basic HTTP server:
Open a another terminal window in the **root of the application folder** (not *src*) and
launch a node static server such as the *live-server* we recommended earlier:
pre.prettyprint.lang-bash
code python -m SimpleHTTPServer 8000
code live-server --open src
:markdown
then point a browser to http://localhost:8000 which should display our simple text message:
**live-server** loads the browser for us, serves the HTML and JavaScript files, and we should see it display our
application message:
figure.image-display
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
:markdown
Alternatively, we might run with a node server such as the *live-server* we recommended earlier:
### Make some changes
**live-server** detects changes to our files and refreshes the browser page for us automatically.
pre.prettyprint.lang-bash
code live-server --port=8000
Try changing the message to "My SECOND Angular 2 app".
:markdown
**live-server** loads the browser for us and refreshes the page as we make
changes to the application. *Check it out!*
The TypeScript compiler running in the first terminal window is watching our source code. It recompiles and produces
the revised *app.js*. The *live-server* sees that change and reloads the browser.
Pretty nice!
.l-main-section
:markdown
@ -228,14 +273,14 @@ include ../../../../_includes/_util-fns
that we installed earlier.
Let's download and install the core set of type definitions files for Angular development
in the root directory of our application.
in the ***src* folder** of our application.
pre.prettyprint.lang-bash
code tsd query angular2 es6-promise rx rx-lite jasmine --action install --save
code tsd install angular2 es6-promise rx rx-lite --save
:markdown
We'll find a ***typings*** folder in the root directory
with subfolders for each of the five downloaded type definition files (angular, es6-promise, rx, rx-lite, jasmine).
We'll find a new ***typings*** folder
with subfolders for each of the downloaded type definition files (angular, es6-promise, rx, and rx-lite).
Type definition files have names ending in ***d.ts***.
There's also a summary ***tsd.d.ts*** file containing references to each of them.