QuickStart replaced by Getting Started (TS/JS) versions
This commit is contained in:
parent
653f41707d
commit
9321c9f0ad
|
@ -0,0 +1,9 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
// Controls the rendering size of tabs in characters. Accepted values: "auto", 2, 4, 6, etc. If set to "auto", the value will be guessed when a file is opened.
|
||||
"editor.tabSize": 2,
|
||||
// Controls if the editor will insert spaces for tabs. Accepted values: "auto", true, false. If set to "auto", the value will be guessed when a file is opened.
|
||||
"editor.insertSpaces": true,
|
||||
// When enabled, will trim trailing whitespace when you save a file.
|
||||
"files.trimTrailingWhitespace": false
|
||||
}
|
|
@ -1,32 +1,25 @@
|
|||
// #docregion dsl
|
||||
(function() {
|
||||
// #docregion
|
||||
|
||||
// #docregion class-w-annotations
|
||||
var AppComponent = ng
|
||||
// #docregion component
|
||||
.Component({
|
||||
selector: 'my-app'
|
||||
})
|
||||
// #enddocregion
|
||||
// #docregion view
|
||||
.View({
|
||||
template: '<h1>My First Angular 2 App</h1>'
|
||||
})
|
||||
// #enddocregion
|
||||
// #docregion class
|
||||
.Class({
|
||||
constructor: function () { }
|
||||
});
|
||||
// #enddocregion
|
||||
// #enddocregion
|
||||
ng.Component({
|
||||
selector: 'my-app',
|
||||
template: '<h1>My First Angular 2 App</h1>'
|
||||
})
|
||||
.Class({
|
||||
constructor: function () { }
|
||||
});
|
||||
// #enddocregion class-w-annotations
|
||||
|
||||
// #docregion bootstrap
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
ng.bootstrap(AppComponent);
|
||||
});
|
||||
// #enddocregion
|
||||
// #enddocregion
|
||||
// #enddocregion bootstrap
|
||||
|
||||
})();
|
||||
// #enddocregion dsl
|
||||
|
||||
/* Non DSL Approach */
|
||||
(function() {
|
||||
|
@ -35,10 +28,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
function AppComponent () {}
|
||||
|
||||
AppComponent.annotations = [
|
||||
new ng.ComponentAnnotation({
|
||||
selector: 'my-app'
|
||||
}),
|
||||
new ng.ViewAnnotation({
|
||||
new ng.Component({
|
||||
selector: 'my-app',
|
||||
template: '<h1 id="output">My First Angular 2 App</h1>'
|
||||
})
|
||||
];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- #docregion -->
|
||||
<!DOCTYPE html>
|
||||
<!-- #docregion -->
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.sfx.dev.js"></script>
|
||||
<script src="node_modules/angular2/bundles/angular2.sfx.dev.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "angular2-getting-started",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "live-server"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"angular2": "2.0.0-alpha.42"
|
||||
},
|
||||
"devDependencies": {
|
||||
"live-server": "^0.8.1"
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
"guide": {
|
||||
"icon": "list",
|
||||
"title": "Step By Step Guide",
|
||||
"title": "Developer Guide",
|
||||
"banner": "Angular 2 is currently in Developer Preview. For <a href='https://docs.angularjs.org/guide'>Angular 1.X Resources</a> please visit <a href='https://angularjs.org/'>Angularjs.org</a>."
|
||||
},
|
||||
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
"title": "Step By Step Guide"
|
||||
},
|
||||
|
||||
"gettingStarted": {
|
||||
"title": "Getting Started"
|
||||
},
|
||||
|
||||
"displaying-data": {
|
||||
"title": "Displaying Data",
|
||||
"intro": "Displaying data is job number one for any good application. In Angular, you bind data to elements in HTML templates and Angular automatically updates the UI as data changes."
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
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
|
||||
## Create a project folder and an *index.html*
|
||||
|
||||
Create a new folder to hold our application project, perhaps like this:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir firstNgApp && cd firstNgApp
|
||||
|
||||
:markdown
|
||||
Then add a new `index.html` file to the project folder and enter the following HTML
|
||||
|
||||
+makeExample('gettingstarted/js/index.html', null, 'index.html')(format="")
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
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.js', 'class-w-annotations')
|
||||
|
||||
: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.js', 'component')
|
||||
|
||||
: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.js', 'view')
|
||||
|
||||
: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.js', 'class')
|
||||
|
||||
: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!
|
||||
|
||||
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
|
||||
## Add TypeScript Type Definition Files (optional)
|
||||
|
||||
"*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.
|
||||
|
||||
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").
|
||||
|
||||
If you haven't already installed the *tsd*, do it now
|
||||
with an npm command entered in a terminal or command window.
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm install -g tsd
|
||||
|
||||
:markdown
|
||||
Now let's download and install the core set of type definitions files for Angular development
|
||||
in the root directory of our application.
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code tsd install angular2 --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).
|
||||
Type definition files have names ending in ***d.ts***.
|
||||
There's also a summary ***tsd.d.ts*** file containing references to each of them.
|
||||
|
||||
Check your editor's documentation for instructions on using the *tsd.d.ts* file to
|
||||
light up type checking and intellisense for these libraries.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## It's all a tree
|
||||
|
||||
We can think of Angular apps as a tree of components.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
And these components could load yet more components until the browser page became a deep tree
|
||||
of nested functionality.
|
||||
|
||||
We'll walk through examples of these scenarios in the following pages.
|
|
@ -0,0 +1,261 @@
|
|||
.callout.is-helpful
|
||||
header Angular is in developer preview
|
||||
p.
|
||||
This quickstart does not reflect the final development process for writing apps with Angular.
|
||||
The following setup is for those who want to try out Angular while it is in developer preview.
|
||||
|
||||
// STEP 1 - Create a project ##########################
|
||||
.l-main-section
|
||||
h2#section-create-project 1. Create a project
|
||||
|
||||
p.
|
||||
This quickstart shows how to write your Angular components in TypeScript. You could instead choose
|
||||
another language such as <a href="/docs/dart/latest/quickstart.html">Dart</a>, ES5, or ES6.
|
||||
|
||||
p.
|
||||
The goal of this quickstart is to write a component in TypeScript that prints a string.
|
||||
We assume you have already installed <a href="https://docs.npmjs.com/getting-started/installing-node">Node and npm</a>.
|
||||
|
||||
p.
|
||||
To get started, create a new empty project directory. All the following commands should be run
|
||||
from this directory.
|
||||
|
||||
p.
|
||||
To get the benefits of TypeScript, we want to have the type definitions available for the compiler and the editor.
|
||||
TypeScript type definitions are typically published in a repo called <a href="http://definitelytyped.org/">DefinitelyTyped</a>.
|
||||
To fetch one of the type definitions to the local directory, we use the <a href="https://www.npmjs.com/package/tsd">tsd package manager</a>.
|
||||
|
||||
code-example.
|
||||
$ npm install -g tsd@^0.6.0
|
||||
$ tsd install angular2 es6-promise rx rx-lite
|
||||
|
||||
p.
|
||||
Next, create two empty files, <code>index.html</code> and <code>app.ts</code>, both at the root of the project:
|
||||
|
||||
code-example.
|
||||
$ touch app.ts index.html
|
||||
|
||||
// STEP 2 - Start the TypeScript compiler ##########################
|
||||
.l-main-section
|
||||
h2#start-tsc 2. Run the TypeScript compiler
|
||||
|
||||
p.
|
||||
Since the browser doesn't understand TypeScript code, we need to run a compiler to translate
|
||||
your code to browser-compliant JavaScript as you work. This quickstart uses the TypeScript
|
||||
compiler in <code>--watch</code> mode, but it is also possible to do the translation in the browser as files
|
||||
are loaded, or configure your editor or IDE to do it.
|
||||
|
||||
code-example.
|
||||
$ npm install -g typescript@^1.5.0
|
||||
$ tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts
|
||||
|
||||
.callout.is-helpful
|
||||
p.
|
||||
Windows users: if you get an error that an option is unknown, you are probably running
|
||||
an older version of TypeScript.
|
||||
See <a href="http://stackoverflow.com/questions/23267858/how-do-i-install-typescript">
|
||||
Stack Overflow: How do I install Typescript</a>
|
||||
|
||||
// STEP 3 - Import Angular ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 3. Import Angular
|
||||
|
||||
p Inside of <code>app.ts</code>, import the type definitions from Angular:
|
||||
code-example.
|
||||
/// <reference path="typings/angular2/angular2.d.ts" />
|
||||
|
||||
p Now your editor should be able to complete the available imports:
|
||||
code-example.
|
||||
import {Component, View, bootstrap} from 'angular2/angular2';
|
||||
|
||||
p.
|
||||
The above import statement uses ES6 module syntax to import three symbols from the Angular module.
|
||||
The module will load at runtime.
|
||||
|
||||
|
||||
// STEP 4 - Create a component ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 4. Define a component
|
||||
|
||||
p.
|
||||
Components structure and represent the UI. This quickstart demonstrates the process of creating a component
|
||||
that has an HTML tag named <strong><code><my-app></code></strong>.
|
||||
|
||||
p.
|
||||
A component consists of two parts, the <strong>component controller</strong>
|
||||
which is an ES6 class, and the <strong>decorators</strong> which tell Angular
|
||||
how to place the component into the page.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
// Annotation section
|
||||
@Component({
|
||||
selector: 'my-app'
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>'
|
||||
})
|
||||
// Component controller
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
|
||||
.l-sub-section
|
||||
h3 @Component and @View annotations
|
||||
|
||||
p.
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (<code>@</code>).
|
||||
p.
|
||||
The <code>@Component</code> annotation defines the HTML tag for the component by specifying the component's CSS selector.
|
||||
p.
|
||||
The <code>@View</code> 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.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
@Component({
|
||||
selector: 'my-app' // Defines the <my-app></my-app> tag
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>' // Defines the inline template for the component
|
||||
})
|
||||
|
||||
p.
|
||||
The annotations above specify an HTML tag of <code><my-app></code>
|
||||
and a template of <code ng-non-bindable><h1>Hello {{ name }}</h1></code>.
|
||||
|
||||
.l-sub-section
|
||||
h3 The template and the component controller
|
||||
|
||||
p.
|
||||
The component controller is the backing of the component's template. This component
|
||||
controller uses TypeScript <code>class</code> syntax.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
|
||||
p.
|
||||
Templates read from their component controllers. Templates have access to any properties
|
||||
or functions placed on the component controller.
|
||||
|
||||
p.
|
||||
The template above binds to a <code>name</code> property through
|
||||
the double-mustache syntax (<code ng-non-bindable>{{ ... }}</code>).
|
||||
The body of the constructor assigns "Alice" to the name property. When the
|
||||
template renders, "Hello Alice" appears instead of
|
||||
<span ng-non-bindable>"Hello {{ name }}"</span>.
|
||||
|
||||
|
||||
|
||||
// STEP 5 - Bootstrap ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 5. Bootstrap
|
||||
|
||||
p.
|
||||
At the bottom of <code>app.ts</code>, call the <code>bootstrap()</code> function
|
||||
to load your new component into its page:
|
||||
|
||||
code-example(language="javaScript").
|
||||
bootstrap(MyAppComponent);
|
||||
|
||||
|
||||
p.
|
||||
The <code>bootstrap()</code> function takes a
|
||||
component as a parameter, enabling the component
|
||||
(as well as any child components it contains) to render.
|
||||
|
||||
|
||||
// STEP 6 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 6. Declare the HTML
|
||||
|
||||
p.
|
||||
Inside the <code>head</code> tag of <code>index.html</code>,
|
||||
include the traceur-runtime and the Angular bundle.
|
||||
Instantiate the <code>my-app</code> component in the <code>body</code>.
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<!-- index.html -->
|
||||
<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://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- The app component created in app.ts -->
|
||||
<my-app></my-app>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
// STEP 7 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 7. Load the component
|
||||
|
||||
p.
|
||||
The last step is to load the module for the <code>my-app</code> component.
|
||||
To do this, we'll use the System library.
|
||||
|
||||
.l-sub-section
|
||||
h3 System.js
|
||||
|
||||
p.
|
||||
<a href="https://github.com/systemjs/systemjs">System</a> is a third-party open-source library that
|
||||
adds ES6 module loading functionality to browsers.
|
||||
|
||||
p.
|
||||
Add the System.js dependency in the <code><head></code> tag, so that
|
||||
it looks like:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<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>
|
||||
</head>
|
||||
|
||||
p.
|
||||
Add the following module-loading code:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<my-app></my-app>
|
||||
<script>System.import('app');</script>
|
||||
|
||||
|
||||
// STEP 8 - Run a local server ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 8. Run a local server
|
||||
|
||||
p Run a local HTTP server, and view <code>index.html</code>.
|
||||
|
||||
p.
|
||||
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>.)
|
||||
|
||||
p For example:
|
||||
|
||||
code-example.
|
||||
# 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
|
||||
|
||||
|
||||
// WHAT'S NEXT... ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile Great job! We'll have the next steps out soon.
|
|
@ -1,261 +1,195 @@
|
|||
.callout.is-helpful
|
||||
header Angular is in developer preview
|
||||
p.
|
||||
This quickstart does not reflect the final development process for writing apps with Angular.
|
||||
The following setup is for those who want to try out Angular while it is in developer preview.
|
||||
include ../../../_includes/_util-fns
|
||||
|
||||
// STEP 1 - Create a project ##########################
|
||||
.l-main-section
|
||||
h2#section-create-project 1. Create a project
|
||||
|
||||
p.
|
||||
This quickstart shows how to write your Angular components in TypeScript. You could instead choose
|
||||
another language such as <a href="/docs/dart/latest/quickstart.html">Dart</a>, ES5, or ES6.
|
||||
|
||||
p.
|
||||
The goal of this quickstart is to write a component in TypeScript that prints a string.
|
||||
We assume you have already installed <a href="https://docs.npmjs.com/getting-started/installing-node">Node and npm</a>.
|
||||
|
||||
p.
|
||||
To get started, create a new empty project directory. All the following commands should be run
|
||||
from this directory.
|
||||
|
||||
p.
|
||||
To get the benefits of TypeScript, we want to have the type definitions available for the compiler and the editor.
|
||||
TypeScript type definitions are typically published in a repo called <a href="http://definitelytyped.org/">DefinitelyTyped</a>.
|
||||
To fetch one of the type definitions to the local directory, we use the <a href="https://www.npmjs.com/package/tsd">tsd package manager</a>.
|
||||
|
||||
code-example.
|
||||
$ npm install -g tsd@^0.6.0
|
||||
$ tsd install angular2 es6-promise rx rx-lite
|
||||
|
||||
p.
|
||||
Next, create two empty files, <code>index.html</code> and <code>app.ts</code>, both at the root of the project:
|
||||
|
||||
code-example.
|
||||
$ touch app.ts index.html
|
||||
|
||||
// STEP 2 - Start the TypeScript compiler ##########################
|
||||
.l-main-section
|
||||
h2#start-tsc 2. Run the TypeScript compiler
|
||||
|
||||
p.
|
||||
Since the browser doesn't understand TypeScript code, we need to run a compiler to translate
|
||||
your code to browser-compliant JavaScript as you work. This quickstart uses the TypeScript
|
||||
compiler in <code>--watch</code> mode, but it is also possible to do the translation in the browser as files
|
||||
are loaded, or configure your editor or IDE to do it.
|
||||
|
||||
code-example.
|
||||
$ npm install -g typescript@^1.5.0
|
||||
$ tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts
|
||||
:markdown
|
||||
Let's start from zero and build a simple Angular 2 application in JavaScript.
|
||||
|
||||
.callout.is-helpful
|
||||
p.
|
||||
Windows users: if you get an error that an option is unknown, you are probably running
|
||||
an older version of TypeScript.
|
||||
See <a href="http://stackoverflow.com/questions/23267858/how-do-i-install-typescript">
|
||||
Stack Overflow: How do I install Typescript</a>
|
||||
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.
|
||||
|
||||
// STEP 3 - Import Angular ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 3. Import Angular
|
||||
:markdown
|
||||
We'll do it in six short steps
|
||||
1. Create a project folder
|
||||
1. Install essential libraries
|
||||
1. Write the root component for our application in *app.js*
|
||||
1. Bootstrap the app
|
||||
1. Create an *index.html*
|
||||
1. Run it
|
||||
|
||||
p Inside of <code>app.ts</code>, import the type definitions from Angular:
|
||||
code-example.
|
||||
/// <reference path="typings/angular2/angular2.d.ts" />
|
||||
|
||||
p Now your editor should be able to complete the available imports:
|
||||
code-example.
|
||||
import {Component, View, bootstrap} from 'angular2/angular2';
|
||||
|
||||
p.
|
||||
The above import statement uses ES6 module syntax to import three symbols from the Angular module.
|
||||
The module will load at runtime.
|
||||
|
||||
|
||||
// STEP 4 - Create a component ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 4. Define a component
|
||||
:markdown
|
||||
## Create a project folder
|
||||
|
||||
**Create a new folder** to hold our application project, perhaps like this:
|
||||
```
|
||||
mkdir angular2-getting-started
|
||||
cd angular2-getting-started
|
||||
```
|
||||
## Install essential libraries
|
||||
|
||||
p.
|
||||
Components structure and represent the UI. This quickstart demonstrates the process of creating a component
|
||||
that has an HTML tag named <strong><code><my-app></code></strong>.
|
||||
We'll use the **npm package manager** to install packages for
|
||||
the libraries and development tools we need:
|
||||
|
||||
p.
|
||||
A component consists of two parts, the <strong>component controller</strong>
|
||||
which is an ES6 class, and the <strong>decorators</strong> which tell Angular
|
||||
how to place the component into the page.
|
||||
>angular2 - the Angular 2 library.
|
||||
|
||||
>[live-server](https://www.npmjs.com/package/live-server "Live-server")
|
||||
a static file server that reloads the browser when files change.
|
||||
|
||||
We could reference the libraries on the web or download them to our project.
|
||||
That isn't a sustainable development process and package loading with npm is really
|
||||
easy once we have it installed.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
// Annotation section
|
||||
@Component({
|
||||
selector: 'my-app'
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>'
|
||||
})
|
||||
// Component controller
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
Don't have npm? [Get it now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
|
||||
because we're going to use it now and repeatedly throughout this documentation.
|
||||
|
||||
:markdown
|
||||
**Open** a terminal window and enter these commands:
|
||||
```
|
||||
npm init -y
|
||||
npm i angular2@2.0.0-alpha.42 --save --save-exact
|
||||
npm i live-server --save-dev
|
||||
```
|
||||
These commands both *install* the packages and *create* an npm configuration
|
||||
file named `package.json`.
|
||||
The essence of our `package.json` should look like this:
|
||||
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
+makeJson('gettingstarted/js/package.json', { paths: 'name, version, dependencies, devDependencies'})
|
||||
|
||||
:markdown
|
||||
There is also a `scripts` section. **Find and replace** it with the following:
|
||||
|
||||
+makeJson('gettingstarted/js/package.json', { paths: 'scripts'})
|
||||
|
||||
:markdown
|
||||
We've just extended our project world with a script command that we'll be running very soon.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Our first Angular component
|
||||
|
||||
Add a new file called *app.js* and paste the following lines:
|
||||
|
||||
+makeExample('gettingstarted/js/app.js', 'class-w-annotations')
|
||||
|
||||
:markdown
|
||||
We're creating a visual component named **`appComponent`** by chaining the
|
||||
`Component` and `Class` methods that belong to the **global Angular namespace, `ng`**.
|
||||
|
||||
```
|
||||
var AppComponent = ng
|
||||
.Component({...})
|
||||
.Class({...})
|
||||
```
|
||||
The **`Component`** method takes a configuration object with two
|
||||
properties. The `selector` property tells Angular that this is a component
|
||||
controlling a host element named "my-app".
|
||||
Angular creates and displays an instance of our `AppComponent`
|
||||
wherever it encounters a `my-app` element.
|
||||
|
||||
The `template` property defines the visual appearance of the component.
|
||||
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` property.
|
||||
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.
|
||||
|
||||
This component class has the bare 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
|
||||
## Bootstrap the app
|
||||
We need to do something to put our application in motion.
|
||||
Add the following to the bottom of the `app.js` file:
|
||||
|
||||
+makeExample('gettingstarted/js/app.js', 'bootstrap')
|
||||
|
||||
:markdown
|
||||
We'll wait for the browser to tell us that it has finished loading
|
||||
all content and then we'll call the Angular `bootstrap` method.
|
||||
|
||||
The `bootstrap` method tells Angular to start the application with our
|
||||
`AppComponent` at the application root.
|
||||
We'd be correct to guess that someday our application will
|
||||
consist of more components arising in tree-like fashion from this root.
|
||||
|
||||
### Wrapped in an IIFE
|
||||
We don't want to pollute the global namespace.
|
||||
We don't need an application namespace yet.
|
||||
So we'll surround the code in a simple IIFE
|
||||
("Immediately Invoked Function Execution")
|
||||
wrapper.
|
||||
|
||||
Here is the entire file:
|
||||
+makeExample('gettingstarted/js/app.js', 'dsl')
|
||||
|
||||
.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/js/index.html', null, 'index.html')(format="")
|
||||
.l-sub-section
|
||||
h3 @Component and @View annotations
|
||||
:markdown
|
||||
Our app loads two script files in the `<head>` element:
|
||||
|
||||
p.
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (<code>@</code>).
|
||||
p.
|
||||
The <code>@Component</code> annotation defines the HTML tag for the component by specifying the component's CSS selector.
|
||||
p.
|
||||
The <code>@View</code> 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.
|
||||
>***angular2.sfx.dev.js***, the Angular 2 development library that puts
|
||||
Angular in the global `ng` namespace.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
@Component({
|
||||
selector: 'my-app' // Defines the <my-app></my-app> tag
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>' // Defines the inline template for the component
|
||||
})
|
||||
>***app.js***, the application JavaScript we just wrote.
|
||||
|
||||
p.
|
||||
The annotations above specify an HTML tag of <code><my-app></code>
|
||||
and a template of <code ng-non-bindable><h1>Hello {{ name }}</h1></code>.
|
||||
In the `<body>`, there's an element called `<my-app>`.
|
||||
This is the placeholder for the *root* of the
|
||||
application. Angular displays our application here.
|
||||
|
||||
.l-sub-section
|
||||
h3 The template and the component controller
|
||||
|
||||
p.
|
||||
The component controller is the backing of the component's template. This component
|
||||
controller uses TypeScript <code>class</code> syntax.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
|
||||
p.
|
||||
Templates read from their component controllers. Templates have access to any properties
|
||||
or functions placed on the component controller.
|
||||
|
||||
p.
|
||||
The template above binds to a <code>name</code> property through
|
||||
the double-mustache syntax (<code ng-non-bindable>{{ ... }}</code>).
|
||||
The body of the constructor assigns "Alice" to the name property. When the
|
||||
template renders, "Hello Alice" appears instead of
|
||||
<span ng-non-bindable>"Hello {{ name }}"</span>.
|
||||
|
||||
|
||||
|
||||
// STEP 5 - Bootstrap ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 5. Bootstrap
|
||||
:markdown
|
||||
## Run it!
|
||||
|
||||
p.
|
||||
At the bottom of <code>app.ts</code>, call the <code>bootstrap()</code> function
|
||||
to load your new component into its page:
|
||||
We need a file server to serve the static assets of our application
|
||||
(*index.html* and *app.js*).
|
||||
|
||||
code-example(language="javaScript").
|
||||
bootstrap(MyAppComponent);
|
||||
For this example we'll use the **live-server** that we installed with `npm`
|
||||
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:
|
||||
|
||||
p.
|
||||
The <code>bootstrap()</code> function takes a
|
||||
component as a parameter, enabling the component
|
||||
(as well as any child components it contains) to render.
|
||||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
That's the `npm` command we added earlier to the `scripts` section of `package.json`
|
||||
|
||||
:markdown
|
||||
**live-server** loads the browser for us and refreshes the page as we make
|
||||
changes to the application.
|
||||
|
||||
In a few moments, a browser tab should open and display
|
||||
|
||||
// STEP 6 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/getting-started/my-first-app.png' alt="Output of getting started app")
|
||||
|
||||
h2#section-angular-create-account 6. Declare the HTML
|
||||
:markdown
|
||||
### Make some changes
|
||||
The `live-server` detects changes to our files and refreshes the browser page for us automatically.
|
||||
|
||||
p.
|
||||
Inside the <code>head</code> tag of <code>index.html</code>,
|
||||
include the traceur-runtime and the Angular bundle.
|
||||
Instantiate the <code>my-app</code> component in the <code>body</code>.
|
||||
Try changing the message to "My SECOND Angular 2 app".
|
||||
The `live-server` sees that change and reloads the browser.
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<!-- index.html -->
|
||||
<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://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- The app component created in app.ts -->
|
||||
<my-app></my-app>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
// STEP 7 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 7. Load the component
|
||||
|
||||
p.
|
||||
The last step is to load the module for the <code>my-app</code> component.
|
||||
To do this, we'll use the System library.
|
||||
|
||||
.l-sub-section
|
||||
h3 System.js
|
||||
|
||||
p.
|
||||
<a href="https://github.com/systemjs/systemjs">System</a> is a third-party open-source library that
|
||||
adds ES6 module loading functionality to browsers.
|
||||
|
||||
p.
|
||||
Add the System.js dependency in the <code><head></code> tag, so that
|
||||
it looks like:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<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>
|
||||
</head>
|
||||
|
||||
p.
|
||||
Add the following module-loading code:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<my-app></my-app>
|
||||
<script>System.import('app');</script>
|
||||
|
||||
|
||||
// STEP 8 - Run a local server ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 8. Run a local server
|
||||
|
||||
p Run a local HTTP server, and view <code>index.html</code>.
|
||||
|
||||
p.
|
||||
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>.)
|
||||
|
||||
p For example:
|
||||
|
||||
code-example.
|
||||
# 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
|
||||
|
||||
|
||||
// WHAT'S NEXT... ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile Great job! We'll have the next steps out soon.
|
||||
Keep `live-server` running in this terminal window and keep trying changes.
|
||||
You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
**Congratulations! We are in business** ... and ready to take
|
||||
our app to the next level.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
"guide": {
|
||||
"icon": "list",
|
||||
"title": "Step By Step Guide",
|
||||
"title": "Developer Guide",
|
||||
"banner": "Angular 2 is currently in Developer Preview. For <a href='https://docs.angularjs.org/guide'>Angular 1.X Resources</a> please visit <a href='https://angularjs.org/'>Angularjs.org</a>."
|
||||
},
|
||||
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
"title": "Step By Step Guide"
|
||||
},
|
||||
|
||||
"gettingStarted": {
|
||||
"title": "Getting Started"
|
||||
},
|
||||
|
||||
"displaying-data": {
|
||||
"title": "Displaying Data",
|
||||
"intro": "Displaying data is job number one for any good application. In Angular, you bind data to elements in HTML templates and Angular automatically updates the UI as data changes."
|
||||
|
|
|
@ -1,326 +1,316 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
In this chapter we’ll setup the environment for testing our sample application and write a few easy Jasmine tests of the app’s simplest parts.
|
||||
In this chapter we’ll setup the environment for testing our sample application and write a few easy Jasmine tests of the app’s simplest parts.
|
||||
We'll learn:
|
||||
- to test one of our application classes
|
||||
- why we prefer our test files to be next to their corresponding source files
|
||||
- to run tests with an `npm` command
|
||||
- load the test file with systemJS
|
||||
|
||||
We learn:
|
||||
- to test one of our application classes
|
||||
- why we prefer our test files to be next to their corresponding source files
|
||||
- to run tests with an `npm` command
|
||||
- load the test file with systemJS
|
||||
.callout.is-helpful
|
||||
header Prior Knowledge
|
||||
:markdown
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
the [Tour of Heroes](./toh-pt1.html) tutorial
|
||||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
:markdown
|
||||
## Create the test-runner HTML
|
||||
|
||||
## Prerequisites
|
||||
Step away from the Jasmine 101 folder and turn to the root folder of the application that we downloaded in the previous chapter.
|
||||
|
||||
We assume
|
||||
Locate the `src` folder that contains the application `index.html`
|
||||
|
||||
- you’ve learned the basics of Angular 2, from this Developers Guide or elsewhere. We won’t re-explain the Angular 2 architecture, its key parts, or the recommended development techniques.
|
||||
you’ve read the [Jasmine 101](./jasmine-testing-101.html) chapter.
|
||||
- you’ve downloaded the [Heroes application we’re about to test](./#). <!-- TODO add link -->
|
||||
Create a new, sibling HTML file, ** `unit-tests.html` ** and copy over the same basic material from the `unit-tests.html` in the [Jasmine 101](./jasmine-testing-101.html) chapter.
|
||||
|
||||
## Create the test-runner HTML
|
||||
```
|
||||
<html>
|
||||
<title>Ng App Unit Tests</title>
|
||||
<link rel="stylesheet" href="../node_modules/jasmine/lib/jasmine.css">
|
||||
|
||||
Step away from the Jasmine 101 folder and turn to the root folder of the application that we downloaded in the previous chapter.
|
||||
<script src="../node_modules/jasmine/lib/jasmine.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/jasmine-html.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/boot.js"></script>
|
||||
|
||||
Locate the `src` folder that contains the application `index.html`
|
||||
</head>
|
||||
|
||||
Create a new, sibling HTML file, ** `unit-tests.html` ** and copy over the same basic material from the `unit-tests.html` in the [Jasmine 101](./jasmine-testing-101.html) chapter.
|
||||
<body>
|
||||
</body>
|
||||
|
||||
```
|
||||
<html>
|
||||
<title>Ng App Unit Tests</title>
|
||||
<link rel="stylesheet" href="../node_modules/jasmine/lib/jasmine.css">
|
||||
</html>
|
||||
```
|
||||
|
||||
<script src="../node_modules/jasmine/lib/jasmine.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/jasmine-html.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/boot.js"></script>
|
||||
We’re picking up right where we left off. All we’ve done is change the title.
|
||||
|
||||
</head>
|
||||
## Update `package.json` for testing
|
||||
|
||||
<body>
|
||||
</body>
|
||||
We’ll assume that the application has `package.json` file that looks more or less like
|
||||
the one we prescribed in the in the “Install npm packages locally” section of the
|
||||
[QuickStart](../quickstart.html).
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
We’re picking up right where we left off. All we’ve done is change the title.
|
||||
|
||||
## Update `package.json` for testing
|
||||
|
||||
We’ll assume that the application has `package.json` file that looks more or less like
|
||||
the one we prescribed in the in the “Install npm packages locally” section of the [Getting Started] chapter.
|
||||
|
||||
We must install the Jasmine package as well:
|
||||
We must install the Jasmine package as well:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm install jasmine-core --save-dev --save-exact
|
||||
code npm install jasmine-core --save-dev --save-exact
|
||||
|
||||
.alert.is-important Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>!
|
||||
|
||||
:markdown
|
||||
Update the Typescript typings aggregation file (`tsd.d.ts`) with the Jasmine typings file.
|
||||
Let’s make one more change to the `package.json` script commands.
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm tsd
|
||||
**Open the `package.json` ** and scroll to the `scripts` node. Look for the command named `test`. Change it to:
|
||||
|
||||
:markdown
|
||||
Let’s make one more change to the `package.json` script commands.
|
||||
"test": "live-server --open=src/unit-tests.html"
|
||||
|
||||
**Open the `package.json` ** and scroll to the `scripts` node. Look for the command named `test`. Change it to:
|
||||
That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote.
|
||||
|
||||
"test": "live-server --open=src/unit-tests.html"
|
||||
## First app tests
|
||||
|
||||
That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote.
|
||||
Believe it or not … we could start testing *some* of our app right away. For example, we can test the `Hero` class:
|
||||
```
|
||||
let nextId = 30;
|
||||
|
||||
## First app tests
|
||||
export class Hero {
|
||||
constructor(
|
||||
public id?: number,
|
||||
public name?: string,
|
||||
public power?: string,
|
||||
public alterEgo?: string
|
||||
) {
|
||||
this.id = id || nextId++;
|
||||
}
|
||||
|
||||
Believe it or not … we could start testing *some* of our app right away. For example, we can test the `Hero` class:
|
||||
```
|
||||
let nextId = 30;
|
||||
clone() { return Hero.clone(this); }
|
||||
|
||||
export class Hero {
|
||||
constructor(
|
||||
public id?: number,
|
||||
public name?: string,
|
||||
public power?: string,
|
||||
public alterEgo?: string
|
||||
) {
|
||||
this.id = id || nextId++;
|
||||
}
|
||||
static clone = (h:any) => new Hero(h.id, h.name, h.alterEgo, h.power);
|
||||
|
||||
clone() { return Hero.clone(this); }
|
||||
static setNextId = (next:number) => nextId = next;
|
||||
}
|
||||
```
|
||||
|
||||
static clone = (h:any) => new Hero(h.id, h.name, h.alterEgo, h.power);
|
||||
Let’s add a couple of simple tests in the `<body>` element.
|
||||
|
||||
static setNextId = (next:number) => nextId = next;
|
||||
}
|
||||
```
|
||||
First, we’ll load the JavaScript file that defines the `Hero` class.
|
||||
|
||||
Let’s add a couple of simple tests in the `<body>` element.
|
||||
```
|
||||
<!-- load the application's Hero definition -->
|
||||
<script src="app/hero.js"></script>
|
||||
```
|
||||
|
||||
First, we’ll load the JavaScript file that defines the `Hero` class.
|
||||
Next, we’ll add an inline script element with the `Hero`tests themselves
|
||||
|
||||
```
|
||||
<!-- load the application's Hero definition -->
|
||||
<script src="app/hero.js"></script>
|
||||
```
|
||||
```
|
||||
<script>
|
||||
// Demo only!
|
||||
describe('Hero', function() {
|
||||
|
||||
Next, we’ll add an inline script element with the `Hero`tests themselves
|
||||
it('has name given in the constructor', function() {
|
||||
var hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.name).toEqual('Super Cat');
|
||||
});
|
||||
|
||||
```
|
||||
<script>
|
||||
// Demo only!
|
||||
describe('Hero', function() {
|
||||
it('has the id given in the constructor', function() {
|
||||
var hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.id).toEqual(1);
|
||||
});
|
||||
|
||||
it('has name given in the constructor', function() {
|
||||
var hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.name).toEqual('Super Cat');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
it('has the id given in the constructor', function() {
|
||||
var hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.id).toEqual(1);
|
||||
});
|
||||
That’s the basic Jasmine we learned back in “Jasmine 101”.
|
||||
|
||||
});
|
||||
</script>
|
||||
```
|
||||
Notice that we surrounded our tests with ** `describe('Hero')` **.
|
||||
|
||||
That’s the basic Jasmine we learned back in “Jasmine 101”.
|
||||
**By convention, our test always begin with a `describe` that identifies the application part under test.**
|
||||
|
||||
Notice that we surrounded our tests with ** `describe('Hero')` **.
|
||||
The description should be sufficient to identify the tested application part and its source file. Almost any convention will do as long as you and your team follow it consistently and are never confused.
|
||||
|
||||
**By convention, our test always begin with a `describe` that identifies the application part under test.**
|
||||
## Run the tests
|
||||
|
||||
The description should be sufficient to identify the tested application part and its source file. Almost any convention will do as long as you and your team follow it consistently and are never confused.
|
||||
Open one terminal window and run the watching compiler command: `npm run tsc`
|
||||
|
||||
## Run the tests
|
||||
Open another terminal window and run live-server: `npm test`
|
||||
|
||||
Open one terminal window and run the watching compiler command: `npm run tsc`
|
||||
|
||||
Open another terminal window and run live-server: `npm test`
|
||||
|
||||
The browser should launch and display the two passing tests:
|
||||
The browser should launch and display the two passing tests:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/first-app-tests/passed-2-specs-0-failures.png' style="width:400px;" alt="Two passing tests")
|
||||
img(src='/resources/images/devguide/first-app-tests/passed-2-specs-0-failures.png' style="width:400px;" alt="Two passing tests")
|
||||
|
||||
:markdown
|
||||
## Critique
|
||||
## Critique
|
||||
|
||||
Is this `Hero` class even worth testing? It’s essentially a property bag with almost no logic. Maybe we should have tested the cloning feature. Maybe we should have tested id generation. We didn’t bother because there wasn’t much to learn by doing that.
|
||||
Is this `Hero` class even worth testing? It’s essentially a property bag with almost no logic. Maybe we should have tested the cloning feature. Maybe we should have tested id generation. We didn’t bother because there wasn’t much to learn by doing that.
|
||||
|
||||
It’s more important to take note of the<span style="background-color: yellow;"> //Demo only </span>comment in the `unit-tests.html`.
|
||||
It’s more important to take note of the `//Demo only` comment in the `unit-tests.html`.
|
||||
|
||||
** We’ll never write real tests in the HTML this way**. It’s nice that we can write *some* of our application tests directly in the HTML. But dumping all of our tests into HTML is not sustainable and even if we didn’t mind that approach, we could only test a tiny fraction of our app this way.
|
||||
** We’ll never write real tests in the HTML this way**. It’s nice that we can write *some* of our application tests directly in the HTML. But dumping all of our tests into HTML is not sustainable and even if we didn’t mind that approach, we could only test a tiny fraction of our app this way.
|
||||
|
||||
We need to relocate these tests to a separate file. Let’s do that next.
|
||||
We need to relocate these tests to a separate file. Let’s do that next.
|
||||
|
||||
## Where do tests go?
|
||||
## Where do tests go?
|
||||
|
||||
Some people like to keep their tests in a `tests` folder parallel to the application source folder.
|
||||
Some people like to keep their tests in a `tests` folder parallel to the application source folder.
|
||||
|
||||
We are not those people. We like our unit tests to be close to the source code that they test. We prefer this approach because
|
||||
- The tests are easy to find
|
||||
- We see at a glance if an application part lacks tests.
|
||||
- Nearby tests can teach us about how the part works; they express the developers intention and reveal how the developer thinks the part should behave under a variety of circumstances.
|
||||
- When we move the source (inevitable), we remember to move the test.
|
||||
- When we rename the source file (inevitable), we remember to rename the test file.
|
||||
We are not those people. We like our unit tests to be close to the source code that they test. We prefer this approach because
|
||||
- The tests are easy to find
|
||||
- We see at a glance if an application part lacks tests.
|
||||
- Nearby tests can teach us about how the part works; they express the developers intention and reveal how the developer thinks the part should behave under a variety of circumstances.
|
||||
- When we move the source (inevitable), we remember to move the test.
|
||||
- When we rename the source file (inevitable), we remember to rename the test file.
|
||||
|
||||
We can’t think of a downside. The server doesn’t care where they are. They are easy to find and distinguish from application files when named conventionally.
|
||||
We can’t think of a downside. The server doesn’t care where they are. They are easy to find and distinguish from application files when named conventionally.
|
||||
|
||||
You may put your tests elsewhere if you wish. We’re putting ours inside the app, next to the source files that they test.
|
||||
You may put your tests elsewhere if you wish. We’re putting ours inside the app, next to the source files that they test.
|
||||
|
||||
## First spec file
|
||||
## First spec file
|
||||
|
||||
**Create** a new file, ** `hero.spec.ts` ** in `src/app` next to `hero.ts`.
|
||||
**Create** a new file, ** `hero.spec.ts` ** in `src/app` next to `hero.ts`.
|
||||
|
||||
Notice the “.spec” suffix in the test file’s filename, appended to the name of the file holding the application part we’re testing.
|
||||
Notice the “.spec” suffix in the test file’s filename, appended to the name of the file holding the application part we’re testing.
|
||||
|
||||
.alert.is-important All of our unit test files follow this .spec naming pattern.
|
||||
.alert.is-important All of our unit test files follow this .spec naming pattern.
|
||||
|
||||
:markdown
|
||||
Move the tests we just wrote in`unit-tests.html` to `hero.spec.ts` and convert them from JavaScript into TypeScript:
|
||||
Move the tests we just wrote in`unit-tests.html` to `hero.spec.ts` and convert them from JavaScript into TypeScript:
|
||||
|
||||
```
|
||||
import {Hero} from './hero';
|
||||
```
|
||||
import {Hero} from './hero';
|
||||
|
||||
describe('Hero', () => {
|
||||
describe('Hero', () => {
|
||||
|
||||
it('has name given in the constructor', () => {
|
||||
let hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.name).toEqual('Super Cat');
|
||||
});
|
||||
it('has name given in the constructor', () => {
|
||||
let hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.name).toEqual('Super Cat');
|
||||
});
|
||||
|
||||
it('has id given in the constructor', () => {
|
||||
let hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.id).toEqual(1);
|
||||
});
|
||||
})
|
||||
it('has id given in the constructor', () => {
|
||||
let hero = new Hero(1, 'Super Cat');
|
||||
expect(hero.id).toEqual(1);
|
||||
});
|
||||
})
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
**Stop and restart the TypeScript compiler**
|
||||
### Import the part we’re testing
|
||||
|
||||
.alert.is-important While the TypeScript compiler is watching for changes to files, it doesn’t always pick up new files to compile.
|
||||
During our conversion to TypeScript, we added an `import {Hero} from './hero' ` statement.
|
||||
|
||||
:markdown
|
||||
### Typing problems
|
||||
If we forgot this import, a TypeScript-aware editor would warn us, with a squiggly red underline, that it can’t find the definition of the `Hero` class.
|
||||
|
||||
The editor may complain that it doesn’t recognize `describe`, `beforeEach`, `it`, and `expect`. These are among the many Jasmine objects in the global namespace.
|
||||
TypeScript doesn’t know what a `Hero` is. It doesn’t know about the script tag back in the `unit-tests.html` that loads the `hero.js` file.
|
||||
|
||||
We can cure the complaints and get intellisense support by adding the Jasmine typings file:
|
||||
### Update unit-tests.html
|
||||
|
||||
Open a new terminal window in the `src` folder and run
|
||||
Next we update the `unit-tests.html` with a reference to our new `hero-spec.ts` file. Delete the inline test code. The revised pertinent HTML looks like this:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code tsd reinstall jasmine --save
|
||||
<script src="app/hero.js"></script>
|
||||
<script src="app/hero.spec.js"></script>
|
||||
|
||||
:markdown
|
||||
Refresh the editor and those particular complaints should disappear
|
||||
## Run and Fail
|
||||
|
||||
### Import the part we’re testing
|
||||
|
||||
During our conversion to TypeScript, we added an `import {Hero} from './hero' ` statement.
|
||||
|
||||
If we forgot this import, a TypeScript-aware editor would warn us, with a squiggly red underline, that it can’t find the definition of the `Hero` class.
|
||||
|
||||
TypeScript doesn’t know what a `Hero` is. It doesn’t know about the script tag back in the `unit-tests.html` that loads the `hero.js` file.
|
||||
|
||||
### Update unit-tests.html
|
||||
|
||||
Next we update the `unit-tests.html` with a reference to our new `hero-spec.ts` file. Delete the inline test code. The revised pertinent HTML looks like this:
|
||||
|
||||
<script src="app/hero.js"></script>
|
||||
<script src="app/hero.spec.js"></script>
|
||||
|
||||
## Run and Fail
|
||||
|
||||
Look over at the browser (live-server will have reloaded it). The browser displays
|
||||
Look over at the browser (live-server will have reloaded it). The browser displays
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/first-app-tests/Jasmine-not-running-tests.png' style="width:400px;" alt="Jasmine not running any tests")
|
||||
img(src='/resources/images/devguide/first-app-tests/Jasmine-not-running-tests.png' style="width:400px;" alt="Jasmine not running any tests")
|
||||
|
||||
:markdown
|
||||
That’s Jasmine saying “**things are _so_ bad that _I’m not running any tests_.**”
|
||||
That’s Jasmine saying “**things are _so_ bad that _I’m not running any tests_.**”
|
||||
|
||||
Open the browser’s Developer Tools (F12, Ctrl-Shift-i). There’s an error:
|
||||
Open the browser’s Developer Tools (F12, Ctrl-Shift-i). There’s an error:
|
||||
```
|
||||
Uncaught ReferenceError: exports is not defined
|
||||
```
|
||||
|
||||
`Uncaught ReferenceError: exports is not defined`
|
||||
## Load tests with systemjs
|
||||
|
||||
## Load tests with systemjs
|
||||
The immediate cause of the error is the `export` statement in `hero.ts`.
|
||||
That error was there all along.
|
||||
It wasn’t a problem until we tried to `import` the `Hero` class in our tests.
|
||||
|
||||
The immediate cause of the error is the `export` statement in `hero.ts`. That error was there all along. It wasn’t a problem until we tried to `import` the `Hero` class in our tests.
|
||||
Our test environment lacks support for module loading.
|
||||
Apparently we can’t simply load our application and test scripts like we do with 3rd party JavaScript libraries.
|
||||
|
||||
Our test environment lacks support for module loading. Apparently we can’t simply load our application and test scripts like we do with 3rd party JavaScript libraries.
|
||||
We are committed to module loading in our application.
|
||||
Our app will call `import`. Our tests must do so too.
|
||||
|
||||
We are committed to module loading in our application. Our app will call `import`. Our tests must do so too.
|
||||
We add module loading support in four steps:
|
||||
|
||||
We add module loading support in four steps:
|
||||
1. add the *systemjs* module management library
|
||||
1. configure *systemjs* to look for JavaScript files by default
|
||||
1. import our test files
|
||||
1. tell Jasmine to run the imported tests
|
||||
|
||||
1. add the *systemjs* module management library
|
||||
1. configure *systemjs* to look for JavaScript files by default
|
||||
1. import our test files
|
||||
1. tell Jasmine to run the imported tests
|
||||
These steps are all clearly visible, in exactly that order, in the following lines that
|
||||
replace the `<body>` contents in `unit-tests.html`:
|
||||
|
||||
These steps are all clearly visible, in exactly that order, in the following lines that
|
||||
replace the `<body>` contents in `unit-tests.html`:
|
||||
```
|
||||
<body>
|
||||
<!-- #1. add the system.js library -->
|
||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
```
|
||||
<body>
|
||||
<!-- #1. add the system.js library -->
|
||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||
<script>
|
||||
// #2. Configure systemjs to use the .js extension
|
||||
// for imports from the app folder
|
||||
System.config({
|
||||
packages: {
|
||||
'app': {defaultExtension: 'js'}
|
||||
}
|
||||
});
|
||||
|
||||
<script>
|
||||
// #2. Configure systemjs to use the .js extension
|
||||
// for imports from the app folder
|
||||
System.config({
|
||||
packages: {
|
||||
'app': {defaultExtension: 'js'}
|
||||
}
|
||||
});
|
||||
// #3. Import the spec file explicitly
|
||||
System.import('app/hero.spec')
|
||||
|
||||
// #3. Import the spec file explicitly
|
||||
System.import('app/hero.spec')
|
||||
// #4. wait for all imports to load ...
|
||||
// then re-execute `window.onload` which
|
||||
// triggers the Jasmine test-runner start
|
||||
// or explain what went wrong
|
||||
.then(window.onload)
|
||||
.catch(console.error.bind(console));
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
// #4. wait for all imports to load ...
|
||||
// then re-execute `window.onload` which
|
||||
// triggers the Jasmine test-runner start
|
||||
// or explain what went wrong
|
||||
.then(window.onload)
|
||||
.catch(console.error.bind(console));
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
Look in the browser window. Our tests pass once again.
|
||||
Look in the browser window. Our tests pass once again.
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/first-app-tests/test-passed-once-again.png' style="width:400px;" alt="Tests passed once again")
|
||||
img(src='/resources/images/devguide/first-app-tests/test-passed-once-again.png' style="width:400px;" alt="Tests passed once again")
|
||||
|
||||
:markdown
|
||||
## Observations
|
||||
## Observations
|
||||
|
||||
System.js demands that we specify a default extension for the filenames that correspond to whatever it is asked to import. Without that default, it would translate an import statement such as `import {Hero} from ‘./here’` to a request for the file named `hero`.
|
||||
### System.config
|
||||
System.js demands that we specify a default extension for the filenames that correspond to whatever it is asked to import.
|
||||
Without that default, it would translate an import statement such as `import {Hero} from ‘./here’` to a request for the file named `hero`.
|
||||
Not `hero.js`. Just plain `hero`. Our server error with “404 - not found” because it doesn’t have a file of that name.
|
||||
|
||||
Not `hero.js`. Just plain `hero`. Our server error with “404 - not found” because it doesn’t have a file of that name.
|
||||
Once configured with a default extension of ‘js’, Systemjs requests `hero.js` which *does* exist and is promptly returned by our server.
|
||||
|
||||
When configured with a default extension of ‘js’, systemjs requests `hero.js` which *does* exist and is promptly returned by our server.
|
||||
### Asynchronous System.import
|
||||
The call to `System.import` shouldn’t surprise us but it’s asynchronous nature might.
|
||||
If we ponder this for a moment, we realize that it must be asynchronous because
|
||||
System.js may have to fetch the corresponding JavaScript file from the server.
|
||||
Accordingly, `System.import` returns a promise and we must wait for that promise to resolve.
|
||||
Only then can Jasmine start evaluating the imported tests.
|
||||
|
||||
The call to `System.import` doesn’t surprise us. But it’s asynchronous nature might. Of course it must be asynchronous; it probably has to fetch the corresponding JavaScript file from the server.
|
||||
### window.onload
|
||||
Jasmine doesn’t have a `start` method. It wires its own start to the browser window’s `load` event.
|
||||
That makes sense if we’re loading our tests with script tags.
|
||||
The browser raises the `load` event when it finishes loading all scripts.
|
||||
|
||||
`System.import` returns a promise. We wait for that promise to resolve and only then can Jasmine start evaluating the imported tests.
|
||||
But we’re not loading test scripts inline anymore.
|
||||
We’re using the systemjs module loader and it won’t be done until long after the browser raised the `load` event.
|
||||
Meanwhile, Jasmine started and ran to completion … with no tests to evaluate … before the import completed.
|
||||
|
||||
Why do we call `window.onload` to start Jasmine? Jasmine doesn’t have a `start` method. It wires its own start to the browser window’s `load` event.
|
||||
So we must wait until the import completes and only then call the window `onLoad` handler.
|
||||
Jasmine re-starts, this time with our imported test queued up.
|
||||
|
||||
That makes sense if we’re loading our tests with script tags. The browser raise the `load` event when it finishes loading all scripts.
|
||||
## What’s Next?
|
||||
We are able to test a part of our application with simple Jasmine tests.
|
||||
The part was a stand-alone class that made no mention or use of Angular.
|
||||
|
||||
But we’re not loading test scripts inline anymore. We’re using the systemjs module loader and it won’t be done until long after the browser raised the `load` event. Jasmine already started and ran to completion … with no tests to evaluate … before the import completed.
|
||||
That’s not rare but it’s not typical either. Most of our application parts make some use of the Angular framework.
|
||||
|
||||
So we wait until the import completes and then pretend that the window `load` event fired again, causing Jasmine to start again, this time with our imported test queued up.
|
||||
|
||||
## What’s Next?
|
||||
We are able to test a part of our application with simple Jasmine tests. That part was a stand-alone class that made no mention or use of Angular.
|
||||
|
||||
That’s not rare but it’s not typical either. Most of our application parts make some use of the Angular framework.
|
||||
|
||||
In the next chapter, we’ll look at a class that does rely on Angular.
|
||||
In the next chapter, we’ll test a class that does rely on Angular.
|
|
@ -1,458 +0,0 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
Let's start from zero and build a super simple Angular 2 application in TypeScript.
|
||||
|
||||
.callout.is-helpful
|
||||
header Don't want TypeScript?
|
||||
:markdown
|
||||
Although we're getting started in TypeScript, you can also write Angular 2 apps
|
||||
in JavaScript and Dart by selecting either of those languages from the combo-box in the banner.
|
||||
|
||||
.l-main-section
|
||||
|
||||
:markdown
|
||||
# The shortest, quickest ...
|
||||
|
||||
Let's put something on the screen in Angular 2 as quickly as we can.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
While we are about to describe steps to take on your development machine,
|
||||
you could take these same steps in an interactive, online coding environment
|
||||
such as [plunker](http://plnkr.co/ "Plunker"). You won't have to
|
||||
install a static server to run the app there.
|
||||
|
||||
If you like what you see - and we think you will - you can repeat this
|
||||
exercise on your own machine later.
|
||||
|
||||
:markdown
|
||||
**Create a new folder** to hold our application project, perhaps like this:
|
||||
```
|
||||
mkdir angular2-getting-started
|
||||
cd angular2-getting-started
|
||||
```
|
||||
|
||||
## Our first Angular component
|
||||
|
||||
**Add a new file** called **`app.ts`** and paste the following lines:
|
||||
|
||||
+makeExample('gettingstarted/ts/src/app/app.ts', null, 'app.ts')
|
||||
|
||||
:markdown
|
||||
We've just defined an Angular 2 **component**,
|
||||
one of the most important Angular 2 features.
|
||||
Components are our primary means of creating application views
|
||||
and supporting them with application logic.
|
||||
|
||||
Ours is an empty, do-nothing class class named `AppComponent`.
|
||||
It would expand with properties and application
|
||||
logic when we're ready to build a substantive application.
|
||||
|
||||
Above the class we see the `@Component` decoration.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
The `@` symbol before the method name identifies `Component` as a decoration.
|
||||
A "decoration" is a TypeScript language feature
|
||||
for creating metadata about the class. Angular finds this metadata
|
||||
in the transpiled JavaScript and responds appropriately.
|
||||
:markdown
|
||||
`@Component` tells Angular that this class *is an Angular component*.
|
||||
The configuration object passed to the `@Component` method has two
|
||||
field, a `selector` and a `template`.
|
||||
|
||||
The `selector` specifies a CSS selector for a custom HTML element named `my-app`.
|
||||
Angular creates and displays an instance of our `AppComponent`
|
||||
wherever it encounters a `my-app` element.
|
||||
|
||||
The `template` field is the component's companion template
|
||||
that tells Angular how to render a view.
|
||||
Our template is a single line of HTML announcing "My First Angular App".
|
||||
|
||||
The `bootstrap` method tells Angular to start the application with this
|
||||
component at the application root.
|
||||
We'd be correct to guess that someday our application will
|
||||
consist of more components arising in tree-like fashion from this root.
|
||||
|
||||
In the top line we imported the `Component`, `View`, and `bootstrap` methods
|
||||
from the Angular 2 library. That's the way we do things now.
|
||||
We no longer expect to find our code or any library code in a global namespace.
|
||||
We `import` exactly what we need, as we need it, from named file and library resources.
|
||||
|
||||
## Add `index.html`
|
||||
|
||||
**Create** an `index.html` file.
|
||||
|
||||
**Paste** the following lines into it ... and we'll discuss them:
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.1.html', null, 'index.html')
|
||||
|
||||
:markdown
|
||||
We see three noteworthy sections of HTML:
|
||||
|
||||
1. We load JavaScript libraries from the web.
|
||||
Let's take them on faith without further discussion.<br/><br/>
|
||||
|
||||
2. We configure something called `System` and ask it to import the
|
||||
application file with our `AppComponent` that we just wrote.
|
||||
`System` is the module loader (from the `system.js` library),
|
||||
a tool that can `import` code;
|
||||
remember the `import` statement in our `AppComponent`?
|
||||
|
||||
We're also asking `system.js` to "transpile" (AKA "compile") our
|
||||
TypeScript source code into JavaScript ... right here in the browser.<br/><br/>
|
||||
|
||||
3. We note the `<my-app>` tag in the `<body>`.
|
||||
That's the custom HTML element we identified in the `@Component` decoration
|
||||
adorning our `AppComponent` class.
|
||||
|
||||
## Run it!
|
||||
|
||||
We need a static file server to serve our application to the browser.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
Don't have a static file server handy? Let's install one of our favorites
|
||||
called [live-server](https://www.npmjs.com/package/live-server "Live-server").
|
||||
|
||||
We'll use the **npm package manager** to install it. Don't have npm?
|
||||
[Go get it](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
|
||||
because we're going to use it now and repeatedly throughout the guide.
|
||||
|
||||
Once you have `npm` installed, open a terminal window and enter
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm install -g live-server
|
||||
|
||||
:markdown
|
||||
Open a terminal window and enter
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code live-server
|
||||
:markdown
|
||||
In a few moments, a browser tab should open and display
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/getting-started/my-first-app.png' alt="Output of getting started app")
|
||||
|
||||
:markdown
|
||||
Congratulations! We are in business.
|
||||
|
||||
.l-main-section
|
||||
|
||||
:markdown
|
||||
## What's wrong with this?
|
||||
|
||||
We were up and running in a hurry and we could explore Angular
|
||||
in this manner for quite some time.
|
||||
|
||||
For a number of reasons this isn't a good approach for building an application.
|
||||
<!-- TODO The formatting here is a little weird. Should improve readability. -->
|
||||
|
||||
* Transpiling TypeScript in the browser becomes tediously slow when our
|
||||
app grows beyond a few files. We certainly won't do that in production. We should learn to
|
||||
compile locally and push the generated JavaScript to the server. We'll need some tools for that.
|
||||
|
||||
|
||||
* Downloading JavaScript libraries from the web is OK for demos but
|
||||
it slows our development. Every time our app reloads, it must refetch these libraries.
|
||||
Don't count on browser caching.
|
||||
Our debugging and live-reload techniques will bust the browser cache. Loading libraries
|
||||
from the web also prevents us from developing our application offline or where connectivity is
|
||||
poor. Let's learn to download the libraries to our machine and serve them locally.
|
||||
|
||||
|
||||
* We want our development cycle to be as fast and friction-free as possible.
|
||||
When we change our code, we want to see the results in the browser immediately.
|
||||
We have tools and procedures for that.
|
||||
|
||||
.l-main-section
|
||||
|
||||
:markdown
|
||||
# Upping our game
|
||||
Let's take a few more steps to put our development on a better foundation. We will
|
||||
|
||||
1. Revise the application project structure for future growth
|
||||
1. Install a few tools and packages
|
||||
1. Revise the **`index.html`** to use local library resources
|
||||
1. Compile the TypeScript locally and watch for changes
|
||||
|
||||
Shut down the `live-server` running in the terminal window (Ctrl-C) and proceed as follows.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Revise the application project structure
|
||||
|
||||
At the moment we're dumping everything into the "angular2-getting-started" **root folder**.
|
||||
Not bad when there are only two files. Not good as our application evolves.
|
||||
|
||||
Let's give our project a little structure.
|
||||
|
||||
We'll add a sub-folder - `src` - to hold project source code and a sub-sub-folder - `src/app` -
|
||||
to hold the application source code.
|
||||
|
||||
In OS/X and Linux:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir src/app
|
||||
|
||||
:markdown
|
||||
In Windows:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir src\app
|
||||
|
||||
:markdown
|
||||
**Move `index.html`** into the **`src`** folder.
|
||||
|
||||
**Move `app.ts`** into the **`src/app`** folder.
|
||||
|
||||
Our project folders should look like this.
|
||||
```
|
||||
angular2-getting-started
|
||||
└── src
|
||||
├── app
|
||||
│ └── app.ts
|
||||
└── index.html
|
||||
```
|
||||
|
||||
.l-main-section
|
||||
|
||||
:markdown
|
||||
## Install npm packages locally
|
||||
|
||||
We'll replace the web-based scripts in our `index.html` with
|
||||
scripts resident on our local machine.
|
||||
We get those scripts by installing two runtime `npm` packages into our project.
|
||||
|
||||
>**angular.js** - the Angular 2 library.
|
||||
|
||||
>**system.js** - an open-source library that provides module loading.
|
||||
|
||||
We'll also install two development tools:
|
||||
|
||||
>**typescript** - the TypeScript compiler
|
||||
|
||||
>**[live-server](https://www.npmjs.com/package/live-server "Live-server")** - the static file server that reloads the browser when files change.
|
||||
We may have loaded it earlier. We're doing it again
|
||||
locally in our project so we are no longer vulnerable to
|
||||
a global uninstall or version change.
|
||||
|
||||
**Open** a terminal window at our application's **root folder**
|
||||
|
||||
Enter these commands:
|
||||
```
|
||||
npm init -y
|
||||
npm i angular2@2.0.0-alpha.42 systemjs@0.19.2 --save --save-exact
|
||||
npm i typescript live-server --save-dev
|
||||
```
|
||||
|
||||
These commands both *install* the packages and *create* an npm `package.json` that will
|
||||
help us develop and maintain our application in future.
|
||||
The essence of our `package.json` should look like this:
|
||||
|
||||
+makeJson('gettingstarted/ts/package.json', { paths: 'name, version, dependencies, devDependencies'})
|
||||
|
||||
:markdown
|
||||
There is also a `scripts` section. **Find and replace** it with the following:
|
||||
|
||||
+makeJson('gettingstarted/ts/package.json', { paths: 'scripts'})
|
||||
|
||||
:markdown
|
||||
We've just extended our project world with script commands
|
||||
that we'll be running very soon.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Update `index.html`
|
||||
|
||||
**Replace** the library scripts section with references to
|
||||
scripts in the packages we just installed.
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', 'libraries')
|
||||
|
||||
:markdown
|
||||
**Update** the `System` configuration script as follows.
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', 'systemjs')
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
We won't be transpiling TypeScript in the browser anymore.
|
||||
We'll do that on our machine and ship the generated JavaScript
|
||||
files to the server.
|
||||
|
||||
We have to re-configure `system.js` to expect JavaScript files
|
||||
with a `.js` extension by default.
|
||||
Someday we might add a `Foo` class to our application in a `foo.ts`
|
||||
file and import it like this
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code import {Foo} from './app/foo'
|
||||
:markdown
|
||||
`system.js`will know to look for a file named `foo.js` in the `src/app` folder.
|
||||
|
||||
That's exactly what we're doing in the last line. We're
|
||||
importing our main application file `app` (the generated `app.js` to be precise)
|
||||
from the `src/app/` folder (we moved it there, remember?)
|
||||
:markdown
|
||||
Here's the final version
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', null, 'index.html')
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Prepare for TypeScript Compilation
|
||||
|
||||
### Add the TypeScript configuration file
|
||||
|
||||
We'll add a configuration file named **`tsconfig.json`**
|
||||
to tell the editor how to interpret our TypeScript code and
|
||||
to simplify the TypeScript compilation command that we'll run very soon.
|
||||
|
||||
**Change to the `src` folder and create a `tsconfig.json`** file with the following content:
|
||||
+makeJson('gettingstarted/ts/src/tsconfig.json', null, 'tsconfig.json')
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
See the [TypeScript configuration appendix](#tsconfig) to learn more about
|
||||
this file and these settings.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Final structure
|
||||
Our final project folder structure should look like this:
|
||||
```
|
||||
angular2-getting-started
|
||||
├── node_modules
|
||||
├── src
|
||||
│ ├── app
|
||||
| │ └── app.ts
|
||||
│ ├── index.html
|
||||
│ └── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Compile the TypeScript to JavaScript
|
||||
|
||||
We no longer transpile TypeScript to JavaScript in the browser.
|
||||
We run the **T**ype**S**cript **C**ompiler (TSC) on our machine instead.
|
||||
|
||||
Open a terminal window in the **root of the application folder** and enter:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
:markdown
|
||||
When it's done 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.
|
||||
|
||||
Our script set the compiler watch option (`-w`) so the
|
||||
compiler stays alive when it's finished.
|
||||
It watches for changes to our **`.ts`** files
|
||||
and recompiles them automatically.
|
||||
|
||||
Leave this command running in the terminal window.
|
||||
You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Run the app!
|
||||
|
||||
Now we are ready to see our app in action.
|
||||
|
||||
Open another terminal window in the **root of the application folder** and
|
||||
launch `live-server` again although this time we'll do it with
|
||||
one of our `npm` script commands:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
**live-server** loads the browser for us, serves the HTML and JavaScript files,
|
||||
and displays our application message once more:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/getting-started/my-first-app.png' alt="Output of getting started app")
|
||||
|
||||
:markdown
|
||||
### Make some changes
|
||||
**`live-server`** detects changes to our files and refreshes the browser page for us automatically.
|
||||
|
||||
Try changing the message to "My SECOND Angular 2 app".
|
||||
|
||||
The TypeScript compiler 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.
|
||||
|
||||
Keep `live-server` running in this terminal window. You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## What have we done?
|
||||
Our first application doesn't do much. It's basically "Hello, World" for Angular 2.
|
||||
|
||||
We kept it simple in our first pass: we wrote a little Angular component,
|
||||
we added some JavaScript libraries to `index.html`, and launched with a
|
||||
static file server. That's about all we'd expect to do for a "Hello, World" app.
|
||||
|
||||
**We have greater ambitions.**
|
||||
|
||||
We won't ask Angular to build "Hello, World".
|
||||
We are asking it to help us build sophisticated applications with sophisticated requirements.
|
||||
|
||||
So we made some strategic technology investments to reach our larger goals
|
||||
|
||||
* our application loads faster with libraries installed locally and
|
||||
we can develop offline if we wish.
|
||||
|
||||
* we're pre-compiling our TypeScript.
|
||||
|
||||
* we're running the compiler and live-server with commands that give us immediate feedback as we make changes.
|
||||
|
||||
The good news is that the overhead of setup is (mostly) behind us.
|
||||
We're about to build a small application that demonstrates the great things
|
||||
we can build with Angular 2.
|
||||
|
||||
<!--TODO: Join us on the [Tour of Heroes](./toh-pt1) -->
|
||||
|
||||
|
||||
<!-- Move this to the Style Guide when we have one -->
|
||||
.l-main-section
|
||||
:markdown
|
||||
<a id="tsconfig"></a>
|
||||
### Appendix: TypeScript configuration
|
||||
We added a TypeScript configuration file (`tsconfig.js`) to our project to
|
||||
guide the compiler as it generates JavaScript files.
|
||||
Get details about `tsconfig.js` from the official
|
||||
[TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json).
|
||||
|
||||
We'd like a moment to discuss the `noImplicitAny` flag.
|
||||
TypeScript developers disagree about whether it should be `true` or `false`.
|
||||
There is no correct answer and we can change the flag later.
|
||||
But our choice now can make a difference in larger projects so it merits
|
||||
discussion.
|
||||
|
||||
When the `noImplicitAny` flag is `false`,
|
||||
the compiler silently defaults the type of a variable to `any` if it cannot infer
|
||||
the type based on how the variable is used. That's what we mean by "implicitly `any`".
|
||||
|
||||
When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer
|
||||
the type, it still generates the JavaScript files but
|
||||
it also reports an error.
|
||||
|
||||
For this project and the other examples in this Developer Guide
|
||||
we set the `noImplicitAny` flag to `false`.
|
||||
Developers who prefer stricter type checking should set the `noImplicitAny` flag to `true`.
|
||||
We can still set a variable's type to `any` if
|
||||
that seems like the best choice. We'd be doing so explicitly after
|
||||
giving the matter some thought.
|
||||
|
||||
If we set the `noImplicitAny` flag to `true`, we may get implicit index errors as well.
|
||||
If we feel these are more annoying than helpful,
|
||||
we can suppress them with the following additional flag.
|
||||
```
|
||||
"suppressImplicitAnyIndexErrors":true
|
||||
```
|
|
@ -1,7 +1,8 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
We’ll write our tests with the [Jasmine test framework](http://jasmine.github.io/2.3/introduction.html). We’ll start by getting *some* tests to work - *any* tests at all.
|
||||
We’ll write our tests with the [Jasmine test framework](http://jasmine.github.io/2.3/introduction.html).
|
||||
We’ll start by getting *some* tests to work - *any* tests at all.
|
||||
|
||||
We will learn
|
||||
- basic Jasmine testing skills
|
||||
|
@ -14,7 +15,8 @@ include ../../../../_includes/_util-fns
|
|||
:markdown
|
||||
## Install npm packages locally
|
||||
|
||||
Next follow all of the steps prescribed in “Install npm packages locally” in the [Getting Started](./gettingStarted.html) chapter.
|
||||
Next follow all of the steps prescribed in “Install npm packages locally” of the
|
||||
[QuickStart](../quickstart.html).
|
||||
|
||||
We’ll also add the Jasmine package via `npm`:
|
||||
|
||||
|
@ -39,13 +41,13 @@ pre.prettyprint.lang-bash
|
|||
Create a new file called`unit-tests.html` and enter the following:
|
||||
```
|
||||
<html>
|
||||
<head>
|
||||
<title>1st Jasmine Tests</title>
|
||||
<link rel="stylesheet" href="../node_modules/jasmine/lib/jasmine.css">
|
||||
|
||||
<script src="../node_modules/jasmine/lib/jasmine.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/jasmine-html.js"></script>
|
||||
<script src="../node_modules/jasmine/lib/boot.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -58,11 +60,11 @@ pre.prettyprint.lang-bash
|
|||
|
||||
We’ll write our first test with inline JavaScript inside the body tag:
|
||||
|
||||
```
|
||||
<script>
|
||||
it('true is true', function(){ expect(true).toEqual(true); });
|
||||
</script>
|
||||
```
|
||||
```
|
||||
<script>
|
||||
it('true is true', function(){ expect(true).toEqual(true); });
|
||||
</script>
|
||||
```
|
||||
|
||||
Now open `unit-tests.html` in a browser and see the Jasmine HTML test output:
|
||||
|
||||
|
@ -73,7 +75,8 @@ figure.image-display
|
|||
It doesn’t get much simpler than that!
|
||||
|
||||
## First TypeScript Test
|
||||
Perhaps too simple. We won’t write our entire test suite inside one HTML file. Let’s **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
|
||||
Perhaps too simple. We won’t write our entire test suite inside one HTML file.
|
||||
Let’s **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
|
@ -82,22 +85,24 @@ figure.image-display
|
|||
.l-main-section
|
||||
:markdown
|
||||
The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But let’s make it more modern with an arrow function:
|
||||
|
||||
it('true is true', () => expect(true).toEqual(true));
|
||||
|
||||
```
|
||||
it('true is true', () => expect(true).toEqual(true));
|
||||
```
|
||||
Now modify `unit-tests.html` to load the script:
|
||||
|
||||
<script src="1st.spec.js"></script>
|
||||
|
||||
```
|
||||
<script src="1st.spec.js"></script>
|
||||
```
|
||||
Hold on! We wrote a TypeScript file but we’re loading a JavaScript file?
|
||||
|
||||
That’s a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next.
|
||||
|
||||
## Prepare for TypeScript
|
||||
|
||||
As we’ve seen before, we first have to tell the compiler how to compile our TypeScript files with a ** `tsconfig.json` **.
|
||||
As we’ve seen before, we first have to tell the compiler how to compile our TypeScript files with
|
||||
a ** `tsconfig.json` **.
|
||||
|
||||
We can copy one from an application we wrote previously and paste it into our src sub-folder. It should look like this:
|
||||
We can copy one from an application we wrote previously and paste it into our src sub-folder.
|
||||
It should look something like this:
|
||||
|
||||
```
|
||||
{
|
||||
|
@ -110,20 +115,6 @@ figure.image-display
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Add *typings* (d.ts) files
|
||||
|
||||
Our editor may complain that it doesn’t know what `it` and `expect` are because it lacks the typing files that describe Jasmine. Let’s take care of that annoyance right now by creating a `tsd.json` file and asking `tsd` to fetch the Jasmine typings file.
|
||||
|
||||
Open a terminal window and enter:
|
||||
```
|
||||
tsd init
|
||||
tsd install jasmine --save
|
||||
```
|
||||
.alert.is-helpful
|
||||
You may have to reload your editor to see the typings files take effect.
|
||||
|
||||
:markdown
|
||||
## Compile and Run
|
||||
|
||||
Compile in the terminal window using the npm script command
|
||||
|
@ -131,10 +122,16 @@ figure.image-display
|
|||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
Our editor and the compiler may complain that they don’t know
|
||||
what `it` and `expect` are because they lack the typing files that describe Jasmine.
|
||||
We can ignore those annoying complaints for now as they are harmless.
|
||||
|
||||
:markdown
|
||||
If we reload the browser, we should see the same Jasmine test-runner output as before.
|
||||
|
||||
But we’ll be evolving these tests rapidly and it would be nice to have the browser refresh automatically as we make changes and recompile.
|
||||
We’ll be evolving these tests rapidly and it would be nice to have the browser refresh automatically as we make changes and recompile.
|
||||
|
||||
Let’s launch with **live-server** in a second terminal window:
|
||||
|
||||
|
@ -152,14 +149,14 @@ pre.prettyprint.lang-bash
|
|||
|
||||
We should wrap this test something that identifies the file. In Jasmine that “something” is a `describe` function. Every test file should have at least one `describe` that identifies the file holding the test(s).
|
||||
|
||||
Here’s what our revised`1st.spec.ts` looks like when wrapped in a `describe`:
|
||||
Here’s what our revised `1st.spec.ts` looks like when wrapped in a `describe`:
|
||||
```
|
||||
describe('1st tests', () => {
|
||||
|
||||
describe('1st tests', () => {
|
||||
|
||||
it('true is true', () => expect(true).toEqual(true));
|
||||
|
||||
});
|
||||
it('true is true', () => expect(true).toEqual(true));
|
||||
|
||||
});
|
||||
```
|
||||
And here’s how the test report displays it.
|
||||
|
||||
figure.image-display
|
||||
|
@ -167,11 +164,11 @@ figure.image-display
|
|||
|
||||
:markdown
|
||||
Let’s add another Jasmine test to `1st.spec.ts`
|
||||
|
||||
it('null is not the same thing as undefined',
|
||||
() => expect(null).not.toEqual(undefined)
|
||||
);
|
||||
|
||||
```
|
||||
it('null is not the same thing as undefined',
|
||||
() => expect(null).not.toEqual(undefined)
|
||||
);
|
||||
```
|
||||
You knew that right? Let’s prove it with this test. The browser should refresh after you paste that test, and show:
|
||||
|
||||
figure.image-display
|
||||
|
|
|
@ -1,148 +1,164 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
We’ll test an Angular pipe in this chapter
|
||||
We’ll test an Angular pipe in this chapter
|
||||
|
||||
An Angular pipe is a declarative way in HTML to transform some input into some displayable output.
|
||||
An Angular pipe is a declarative way in HTML to transform some input into some displayable output.
|
||||
|
||||
We’ll look at our app’s custom `InitCapsPipe` that converts a string of words into a string of capitalized words.
|
||||
We’ll look at our app’s custom `InitCapsPipe` that converts a string of words into a string of capitalized words.
|
||||
|
||||
We use it our `hero-detail.component.html` template to turn a hero name like “eeny weenie” into “Eeny Weenie”
|
||||
We use it our `hero-detail.component.html` template to turn a hero name like “eeny weenie” into “Eeny Weenie”
|
||||
|
||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
||||
|
||||
code-example(format="linenums").
|
||||
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
|
||||
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
|
||||
|
||||
:markdown
|
||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
||||
|
||||
```
|
||||
import {Pipe} from 'angular2/angular2';
|
||||
```
|
||||
import {Pipe} from 'angular2/angular2';
|
||||
|
||||
@Pipe({ name: 'initCaps' })
|
||||
export class InitCapsPipe {
|
||||
transform(value: string) {
|
||||
return value.toLowerCase().replace(/(?:^|\s)[a-z]/g, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
@Pipe({ name: 'initCaps' })
|
||||
export class InitCapsPipe {
|
||||
transform(value: string) {
|
||||
return value.toLowerCase().replace(/(?:^|\s)[a-z]/g, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this chapter we will:
|
||||
- add the Angular 2 library to our test harness
|
||||
- test this custom Angular pipe class
|
||||
- load multiple test files in our test harness, using system.js
|
||||
In this chapter we will:
|
||||
- add the Angular 2 library to our test harness
|
||||
- test this custom Angular pipe class
|
||||
- load multiple test files in our test harness, using system.js
|
||||
|
||||
.callout.is-helpful
|
||||
header Prior Knowledge
|
||||
p This chapter assumes familiarity with basic Angular 2 concepts, the tools we introduced in <a href="./gettingStarted.html">Getting Started</a> and <a href="./toh-pt1.html">Tour of Heroes</a>, and earlier chapters of this Unit Testing series.
|
||||
header Prior Knowledge
|
||||
:markdown
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
the [Tour of Heroes](./toh-pt1.html) tutorial
|
||||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
|
||||
:markdown
|
||||
## Add the Angular library
|
||||
Looking back at `unit-tests.html` we realize that we have not loaded the Angular library. Yet we were able to load and test the application’s `Hero` class.
|
||||
## Add the Angular library
|
||||
Looking back at `unit-tests.html` we realize that we have not loaded the Angular library.
|
||||
Yet we were able to load and test the application’s `Hero` class.
|
||||
|
||||
**We were lucky!** The `Hero` class has no dependence on Angular. If it had depended on Angular, we’d still be staring at the Jasmine “big-time fail” screen:
|
||||
**We were lucky!** The `Hero` class has no dependence on Angular.
|
||||
If it had depended on Angular, we’d still be staring at the Jasmine “big-time fail” screen:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/testing-an-angular-pipe/big-time-fail-screen.png' style="width:400px;" alt="Jasmine's' big time fail screen")
|
||||
img(src='/resources/images/devguide/testing-an-angular-pipe/big-time-fail-screen.png'
|
||||
style="width:400px;" alt="Jasmine's' big time fail screen")
|
||||
|
||||
:markdown
|
||||
If we then opened the browser’s Developer Tools (F12, Ctrl-Shift-I) and looked in the console window, we would see.
|
||||
If we then opened the browser’s Developer Tools (F12, Ctrl-Shift-I) and looked
|
||||
in the console window, we would see that SystemJS
|
||||
tried to load Angular and couldn't find it.
|
||||
|
||||
`GET http://127.0.0.1:8080/src/angular2/angular2 404 (Not Found)` <!--TODO probably belongs
|
||||
in a code box not as an inline code style -->
|
||||
```
|
||||
GET http://127.0.0.1:8080/src/angular2/angular2 404 (Not Found)
|
||||
```
|
||||
We are writing an Angular application afterall and
|
||||
we were going to need Angular sooner or later. That time has come.
|
||||
The `InitCapsPiep` clearly depends on Angular as is clear in the first few lines:
|
||||
```
|
||||
import {Pipe} from 'angular2/angular2';
|
||||
|
||||
It is missing indeed!
|
||||
@Pipe({ name: 'initCaps' })
|
||||
export class InitCapsPipe {
|
||||
```
|
||||
**Open** `unit-tests.html`
|
||||
|
||||
We are going to need Angular sooner or later. We are writing an Angular application and we expect to use it at some point.
|
||||
**Find** the `src="../node_modules/systemjs/dist/system.src.js"></script>`
|
||||
|
||||
That moment has arrived! The `InitCapsPiep` clearly depends on Angular. That much is clear in the first few lines:
|
||||
**Replace** Step #1 with these two scripts:
|
||||
```
|
||||
<!-- #1. add the system.js and angular libraries -->
|
||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||
```
|
||||
## Add another spec file
|
||||
|
||||
import {Pipe} from 'angular2/angular2';
|
||||
**Create** an *`init-caps-pipe.spec.ts`** next to `init-caps-pipes.ts` in `src/app`
|
||||
|
||||
@Pipe({ name: 'initCaps' })
|
||||
export class InitCapsPipe {
|
||||
**Stop and restart the TypeScript compiler** to ensure we compile the new file.
|
||||
|
||||
Let’s not wait for trouble. Load the Angular library now… along with its essential companion, the `traceur-runtime`.
|
||||
**Add** the following lines of rather obvious Jasmine test code
|
||||
```
|
||||
import {InitCapsPipe} from './init-caps-pipe';
|
||||
|
||||
**Open** `unit-tests.html`
|
||||
describe('InitCapsPipe', () => {
|
||||
let pipe:InitCapsPipe;
|
||||
|
||||
**Find** the `src="../node_modules/systemjs/dist/system.src.js"></script>`
|
||||
beforeEach(() => {
|
||||
pipe = new InitCapsPipe();
|
||||
});
|
||||
|
||||
**Replace** Step #1 with these two scripts:
|
||||
it('transforms "abc" to "Abc"', () => {
|
||||
expect(pipe.transform('abc')).toEqual('Abc');
|
||||
});
|
||||
|
||||
<!-- #1. add the system.js and angular libraries -->
|
||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||
it('transforms "abc def" to "Abc Def"', () => {
|
||||
expect(pipe.transform('abc def')).toEqual('Abc Def');
|
||||
});
|
||||
|
||||
## Add another spec file
|
||||
it('leaves "Abc Def" unchanged', () => {
|
||||
expect(pipe.transform('Abc Def')).toEqual('Abc Def');
|
||||
});
|
||||
});
|
||||
```
|
||||
Note that each test is short (one line in our case).
|
||||
It has a clear label that accurately describes the test. And it makes exactly one expectation.
|
||||
|
||||
**Create** an ** `init-caps-pipe.spec.ts` ** next to `init-caps-pipes.ts` in `src/app`
|
||||
Anyone can read these tests and understand quickly what the test does and what the pipe does.
|
||||
If one of the tests fails, we know which expected behavior is no longer true.
|
||||
We’ll have little trouble maintaining these tests and adding more like them as we encounter new conditions to explore.
|
||||
|
||||
**Stop and restart the TypeScript compiler** to ensure we compile the new file.
|
||||
That’s the way we like our tests!
|
||||
|
||||
**Add** the following lines of unremarkable Jasmine test code
|
||||
## Add this spec to `unit-tests.html`
|
||||
|
||||
import {InitCapsPipe} from './init-caps-pipe';
|
||||
Now let’s wire our new spec file into the HTML test harness.
|
||||
|
||||
describe('InitCapsPipe', () => {
|
||||
let pipe:InitCapsPipe;
|
||||
Open `unit-tests.html`. Find `System.import('app/hero.spec')`.
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new InitCapsPipe();
|
||||
});
|
||||
Hmm. We can’t just add `System.import('app/init-caps-pipe.spec')`.
|
||||
|
||||
it('transforms "abc" to "Abc"', () => {
|
||||
expect(pipe.transform('abc')).toEqual('Abc');
|
||||
});
|
||||
The first `System.import` returns a promise as does this second import.
|
||||
We can’t run any of the Jasmine tests until **both imports are finished**.
|
||||
|
||||
it('transforms "abc def" to "Abc Def"', () => {
|
||||
expect(pipe.transform('abc def')).toEqual('Abc Def');
|
||||
});
|
||||
|
||||
it('leaves "Abc Def" unchanged', () => {
|
||||
expect(pipe.transform('Abc Def')).toEqual('Abc Def');
|
||||
});
|
||||
});
|
||||
|
||||
Note that each test is short (one line in our case). It has a clear label that accurately describes the test. And it makes exactly one expectation.
|
||||
|
||||
Anyone can read these tests and understand quickly what the test does and what the pipe does. If one of the tests fails, we know which expected behavior is no longer true. We’ll have little trouble maintaining these tests and adding more like them as we encounter new conditions to explore.
|
||||
|
||||
That’s the way we like our tests!
|
||||
|
||||
## Add this spec to `unit-tests.html`
|
||||
|
||||
Now let’s wire our new spec file into the HTML test harness.
|
||||
|
||||
Open `unit-tests.html`. Find `System.import('app/hero.spec')`.
|
||||
|
||||
Hmm. We can’t just add `System.import('app/init-caps-pipe.spec')`.
|
||||
|
||||
The first `System.import` returns a promise as does this second import. We can’t run any of the Jasmine tests until **both imports are finished**.
|
||||
|
||||
Fortunately, we can create a new `Promise` that wraps both import promises and waits for both to finish loading.
|
||||
|
||||
// #3. Import the spec files explicitly
|
||||
Promise.all([
|
||||
System.import('app/hero.spec'),
|
||||
System.import('app/init-caps-pipe.spec')
|
||||
])
|
||||
|
||||
Try it. The browser should refresh and show
|
||||
Fortunately, we can create a new `Promise` that wraps both import promises and waits
|
||||
for both to finish loading.
|
||||
```
|
||||
// #3. Import the spec files explicitly
|
||||
Promise.all([
|
||||
System.import('app/hero.spec'),
|
||||
System.import('app/init-caps-pipe.spec')
|
||||
])
|
||||
```
|
||||
Try it. The browser should refresh and show
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/testing-an-angular-pipe/5-specs-0-failures.png' style="width:400px;" alt="import promises 5 specs, 0 failures")
|
||||
img(src='/resources/images/devguide/testing-an-angular-pipe/5-specs-0-failures.png'
|
||||
style="width:400px;" alt="import promises 5 specs, 0 failures")
|
||||
|
||||
:markdown
|
||||
We have a pattern for adding new tests.
|
||||
We have a pattern for adding new tests.
|
||||
|
||||
In future, when we add a new spec, we add another `System.import('app/some.spec')` to the array argument passed to `Promise.all`.
|
||||
In future, when we add a new spec, we add another `System.import('app/some.spec')` to
|
||||
the array argument passed to `Promise.all`.
|
||||
|
||||
## What’s Next?
|
||||
## What’s Next?
|
||||
|
||||
Now we can test parts of our application that we *load* asynchronously with system.js.
|
||||
Now we can test parts of our application that we *load* asynchronously with system.js.
|
||||
|
||||
What about testing parts that *are themselves asynchronous*?
|
||||
What about testing parts that *are themselves asynchronous*?
|
||||
|
||||
In the next chapter we’ll test a service with a public asynchronous method that fetches heroes from a remote server.
|
||||
In the next chapter we’ll test a service with a public asynchronous method that fetches heroes
|
||||
from a remote server.
|
|
@ -63,12 +63,12 @@ include ../../../../_includes/_util-fns
|
|||
:markdown
|
||||
# Once Upon a Time
|
||||
|
||||
Every story starts somewhere. Our story starts where the [Getting Started chapter]('./gettingstarted') ends.
|
||||
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart) ends.
|
||||
|
||||
Follow the "Getting Started" steps. They provide the prerequisites, the folder structure,
|
||||
Follow the "QuickStart" steps. They provide the prerequisites, the folder structure,
|
||||
and the core files for our Tour of Heroes.
|
||||
|
||||
Copy the "Getting Started" code to a new folder and rename the folder `angular2-tour-of-heroes`.
|
||||
Copy the "QuickStart" code to a new folder and rename the folder `angular2-tour-of-heroes`.
|
||||
We should have the following structure:
|
||||
|
||||
code-example.
|
||||
|
|
|
@ -113,7 +113,12 @@ figure.image-display
|
|||
|
||||
.callout.is-helpful
|
||||
header How to Use This Guide
|
||||
p The three Unit Testing chapters build upon each other. We recommend reading them in order. We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools we introduced in <a href="./gettingStarted.html">Getting Started</a> and <a href="./toh-pt1.html">Tour of Heroes</a> such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
:markdown
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
the [Tour of Heroes](./toh-pt1.html) tutorial
|
||||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
|
||||
:markdown
|
||||
Let’s get started!
|
|
@ -0,0 +1,260 @@
|
|||
.callout.is-helpful
|
||||
header Angular is in developer preview
|
||||
p.
|
||||
This quickstart does not reflect the final development process for writing apps with Angular.
|
||||
The following setup is for those who want to try out Angular while it is in developer preview.
|
||||
|
||||
// STEP 1 - Create a project ##########################
|
||||
.l-main-section
|
||||
h2#section-create-project 1. Create a project
|
||||
|
||||
p.
|
||||
This quickstart shows how to write your Angular components in TypeScript. You could instead choose
|
||||
another language such as <a href="/docs/dart/latest/quickstart.html">Dart</a>, ES5, or ES6.
|
||||
|
||||
p.
|
||||
The goal of this quickstart is to write a component in TypeScript that prints a string.
|
||||
We assume you have already installed <a href="https://docs.npmjs.com/getting-started/installing-node">Node and npm</a>.
|
||||
|
||||
p.
|
||||
To get started, create a new empty project directory. All the following commands should be run
|
||||
from this directory.
|
||||
|
||||
p.
|
||||
To get the benefits of TypeScript, we want to have the type definitions available for the compiler and the editor.
|
||||
TypeScript type definitions are typically published in a repo called <a href="http://definitelytyped.org/">DefinitelyTyped</a>.
|
||||
To fetch one of the type definitions to the local directory, we use the <a href="https://www.npmjs.com/package/tsd">tsd package manager</a>.
|
||||
|
||||
code-example.
|
||||
$ npm install -g tsd@^0.6.0
|
||||
$ tsd install angular2 es6-promise rx rx-lite
|
||||
|
||||
p.
|
||||
Next, create two empty files, <code>index.html</code> and <code>app.ts</code>, both at the root of the project:
|
||||
|
||||
code-example.
|
||||
$ touch app.ts index.html
|
||||
|
||||
// STEP 2 - Start the TypeScript compiler ##########################
|
||||
.l-main-section
|
||||
h2#start-tsc 2. Run the TypeScript compiler
|
||||
|
||||
p.
|
||||
Since the browser doesn't understand TypeScript code, we need to run a compiler to translate
|
||||
your code to browser-compliant JavaScript as you work. This quickstart uses the TypeScript
|
||||
compiler in <code>--watch</code> mode, but it is also possible to do the translation in the browser as files
|
||||
are loaded, or configure your editor or IDE to do it.
|
||||
|
||||
code-example.
|
||||
$ npm install -g typescript@^1.5.0-beta
|
||||
$ tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts
|
||||
|
||||
.callout.is-helpful
|
||||
p.
|
||||
Windows users: if you get an error that an option is unknown, you are probably running
|
||||
an older version of TypeScript.
|
||||
See <a href="http://stackoverflow.com/questions/23267858/how-do-i-install-typescript">
|
||||
Stack Overflow: How do I install Typescript</a>
|
||||
|
||||
// STEP 3 - Import Angular ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 3. Import Angular
|
||||
|
||||
p Inside of <code>app.ts</code>, import the type definitions from Angular:
|
||||
code-example.
|
||||
/// <reference path="typings/angular2/angular2.d.ts" />
|
||||
|
||||
p Now your editor should be able to complete the available imports:
|
||||
code-example.
|
||||
import {Component, View, bootstrap} from 'angular2/angular2';
|
||||
|
||||
p.
|
||||
The above import statement uses ES6 module syntax to import three symbols from the Angular module.
|
||||
The module will load at runtime.
|
||||
|
||||
|
||||
// STEP 4 - Create a component ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 4. Define a component
|
||||
|
||||
p.
|
||||
Components structure and represent the UI. This quickstart demonstrates the process of creating a component
|
||||
that has an HTML tag named <strong><code><my-app></code></strong>.
|
||||
|
||||
p.
|
||||
A component consists of two parts, the <strong>component controller</strong>
|
||||
which is an ES6 class, and the <strong>decorators</strong> which tell Angular
|
||||
how to place the component into the page.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
// Annotation section
|
||||
@Component({
|
||||
selector: 'my-app'
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>'
|
||||
})
|
||||
// Component controller
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
|
||||
.l-sub-section
|
||||
h3 @Component and @View annotations
|
||||
|
||||
p.
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (<code>@</code>).
|
||||
p.
|
||||
The <code>@Component</code> annotation defines the HTML tag for the component by specifying the component's CSS selector.
|
||||
p.
|
||||
The <code>@View</code> 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.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
@Component({
|
||||
selector: 'my-app' // Defines the <my-app></my-app> tag
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>' // Defines the inline template for the component
|
||||
})
|
||||
|
||||
p.
|
||||
The annotations above specify an HTML tag of <code><my-app></code>
|
||||
and a template of <code ng-non-bindable><h1>Hello {{ name }}</h1></code>.
|
||||
|
||||
.l-sub-section
|
||||
h3 The template and the component controller
|
||||
|
||||
p.
|
||||
The component controller is the backing of the component's template. This component
|
||||
controller uses TypeScript <code>class</code> syntax.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
|
||||
p.
|
||||
Templates read from their component controllers. Templates have access to any properties
|
||||
or functions placed on the component controller.
|
||||
|
||||
p.
|
||||
The template above binds to a <code>name</code> property through
|
||||
the double-mustache syntax (<code ng-non-bindable>{{ ... }}</code>).
|
||||
The body of the constructor assigns "Alice" to the name property. When the
|
||||
template renders, "Hello Alice" appears instead of
|
||||
<span ng-non-bindable>"Hello {{ name }}"</span>.
|
||||
|
||||
|
||||
|
||||
// STEP 5 - Bootstrap ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 5. Bootstrap
|
||||
|
||||
p.
|
||||
At the bottom of <code>app.ts</code>, call the <code>bootstrap()</code> function
|
||||
to load your new component into its page:
|
||||
|
||||
code-example(language="javaScript").
|
||||
bootstrap(MyAppComponent);
|
||||
|
||||
|
||||
p.
|
||||
The <code>bootstrap()</code> function takes a
|
||||
component as a parameter, enabling the component
|
||||
(as well as any child components it contains) to render.
|
||||
|
||||
|
||||
// STEP 6 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 6. Declare the HTML
|
||||
|
||||
p.
|
||||
Inside the <code>head</code> tag of <code>index.html</code>,
|
||||
include the traceur-runtime and the Angular bundle.
|
||||
Instantiate the <code>my-app</code> component in the <code>body</code>.
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<!-- index.html -->
|
||||
<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://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- The app component created in app.ts -->
|
||||
<my-app></my-app>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
// STEP 7 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 7. Load the component
|
||||
|
||||
p.
|
||||
The last step is to load the module for the <code>my-app</code> component.
|
||||
To do this, we'll use the System library.
|
||||
|
||||
.l-sub-section
|
||||
h3 System.js
|
||||
|
||||
p.
|
||||
<a href="https://github.com/systemjs/systemjs">System</a> is a third-party open-source library that
|
||||
adds ES6 module loading functionality to browsers.
|
||||
|
||||
p.
|
||||
Add the System.js dependency in the <code><head></code> tag, so that
|
||||
it looks like:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<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>
|
||||
</head>
|
||||
|
||||
p.
|
||||
Add the following module-loading code:
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<my-app></my-app>
|
||||
<script>System.import('app');</script>
|
||||
|
||||
|
||||
// STEP 8 - Run a local server ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 8. Run a local server
|
||||
|
||||
p Run a local HTTP server, and view <code>index.html</code>.
|
||||
|
||||
p.
|
||||
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:
|
||||
|
||||
code-example.
|
||||
# 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
|
||||
|
||||
|
||||
// WHAT'S NEXT... ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile Great job! We'll have the next steps out soon.
|
|
@ -1,260 +1,459 @@
|
|||
.callout.is-helpful
|
||||
header Angular is in developer preview
|
||||
p.
|
||||
This quickstart does not reflect the final development process for writing apps with Angular.
|
||||
The following setup is for those who want to try out Angular while it is in developer preview.
|
||||
include ../../../_includes/_util-fns
|
||||
|
||||
// STEP 1 - Create a project ##########################
|
||||
.l-main-section
|
||||
h2#section-create-project 1. Create a project
|
||||
|
||||
p.
|
||||
This quickstart shows how to write your Angular components in TypeScript. You could instead choose
|
||||
another language such as <a href="/docs/dart/latest/quickstart.html">Dart</a>, ES5, or ES6.
|
||||
|
||||
p.
|
||||
The goal of this quickstart is to write a component in TypeScript that prints a string.
|
||||
We assume you have already installed <a href="https://docs.npmjs.com/getting-started/installing-node">Node and npm</a>.
|
||||
|
||||
p.
|
||||
To get started, create a new empty project directory. All the following commands should be run
|
||||
from this directory.
|
||||
|
||||
p.
|
||||
To get the benefits of TypeScript, we want to have the type definitions available for the compiler and the editor.
|
||||
TypeScript type definitions are typically published in a repo called <a href="http://definitelytyped.org/">DefinitelyTyped</a>.
|
||||
To fetch one of the type definitions to the local directory, we use the <a href="https://www.npmjs.com/package/tsd">tsd package manager</a>.
|
||||
|
||||
code-example.
|
||||
$ npm install -g tsd@^0.6.0
|
||||
$ tsd install angular2 es6-promise rx rx-lite
|
||||
|
||||
p.
|
||||
Next, create two empty files, <code>index.html</code> and <code>app.ts</code>, both at the root of the project:
|
||||
|
||||
code-example.
|
||||
$ touch app.ts index.html
|
||||
|
||||
// STEP 2 - Start the TypeScript compiler ##########################
|
||||
.l-main-section
|
||||
h2#start-tsc 2. Run the TypeScript compiler
|
||||
|
||||
p.
|
||||
Since the browser doesn't understand TypeScript code, we need to run a compiler to translate
|
||||
your code to browser-compliant JavaScript as you work. This quickstart uses the TypeScript
|
||||
compiler in <code>--watch</code> mode, but it is also possible to do the translation in the browser as files
|
||||
are loaded, or configure your editor or IDE to do it.
|
||||
|
||||
code-example.
|
||||
$ npm install -g typescript@^1.5.0-beta
|
||||
$ tsc --watch -m commonjs -t es5 --emitDecoratorMetadata app.ts
|
||||
:markdown
|
||||
Let's start from zero and build a super simple Angular 2 application in TypeScript.
|
||||
|
||||
.callout.is-helpful
|
||||
p.
|
||||
Windows users: if you get an error that an option is unknown, you are probably running
|
||||
an older version of TypeScript.
|
||||
See <a href="http://stackoverflow.com/questions/23267858/how-do-i-install-typescript">
|
||||
Stack Overflow: How do I install Typescript</a>
|
||||
header Don't want TypeScript?
|
||||
:markdown
|
||||
Although we're getting started in TypeScript, you can also write Angular 2 apps
|
||||
in JavaScript and Dart by selecting either of those languages from the combo-box in the banner.
|
||||
|
||||
// STEP 3 - Import Angular ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 3. Import Angular
|
||||
|
||||
p Inside of <code>app.ts</code>, import the type definitions from Angular:
|
||||
code-example.
|
||||
/// <reference path="typings/angular2/angular2.d.ts" />
|
||||
|
||||
p Now your editor should be able to complete the available imports:
|
||||
code-example.
|
||||
import {Component, View, bootstrap} from 'angular2/angular2';
|
||||
|
||||
p.
|
||||
The above import statement uses ES6 module syntax to import three symbols from the Angular module.
|
||||
The module will load at runtime.
|
||||
|
||||
|
||||
// STEP 4 - Create a component ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-angular-create-account 4. Define a component
|
||||
:markdown
|
||||
# The shortest, quickest ...
|
||||
|
||||
p.
|
||||
Components structure and represent the UI. This quickstart demonstrates the process of creating a component
|
||||
that has an HTML tag named <strong><code><my-app></code></strong>.
|
||||
|
||||
p.
|
||||
A component consists of two parts, the <strong>component controller</strong>
|
||||
which is an ES6 class, and the <strong>decorators</strong> which tell Angular
|
||||
how to place the component into the page.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
// Annotation section
|
||||
@Component({
|
||||
selector: 'my-app'
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>'
|
||||
})
|
||||
// Component controller
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
Let's put something on the screen in Angular 2 as quickly as we can.
|
||||
|
||||
.l-sub-section
|
||||
h3 @Component and @View annotations
|
||||
:markdown
|
||||
While we are about to describe steps to take on your development machine,
|
||||
you could take these same steps in an interactive, online coding environment
|
||||
such as [plunker](http://plnkr.co/ "Plunker"). You won't have to
|
||||
install a static server to run the app there.
|
||||
|
||||
p.
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (<code>@</code>).
|
||||
p.
|
||||
The <code>@Component</code> annotation defines the HTML tag for the component by specifying the component's CSS selector.
|
||||
p.
|
||||
The <code>@View</code> 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.
|
||||
If you like what you see - and we think you will - you can repeat this
|
||||
exercise on your own machine later.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
@Component({
|
||||
selector: 'my-app' // Defines the <my-app></my-app> tag
|
||||
})
|
||||
@View({
|
||||
template: '<h1>Hello {{ name }}</h1>' // Defines the inline template for the component
|
||||
})
|
||||
:markdown
|
||||
**Create a new folder** to hold our application project, perhaps like this:
|
||||
```
|
||||
mkdir angular2-getting-started
|
||||
cd angular2-getting-started
|
||||
```
|
||||
|
||||
p.
|
||||
The annotations above specify an HTML tag of <code><my-app></code>
|
||||
and a template of <code ng-non-bindable><h1>Hello {{ name }}</h1></code>.
|
||||
## Our first Angular component
|
||||
|
||||
**Add a new file** called **`app.ts`** and paste the following lines:
|
||||
|
||||
+makeExample('gettingstarted/ts/src/app/app.ts', null, 'app.ts')
|
||||
|
||||
:markdown
|
||||
We've just defined an Angular 2 **component**,
|
||||
one of the most important Angular 2 features.
|
||||
Components are our primary means of creating application views
|
||||
and supporting them with application logic.
|
||||
|
||||
Ours is an empty, do-nothing class class named `AppComponent`.
|
||||
It would expand with properties and application
|
||||
logic when we're ready to build a substantive application.
|
||||
|
||||
Above the class we see the `@Component` decoration.
|
||||
|
||||
.l-sub-section
|
||||
h3 The template and the component controller
|
||||
:markdown
|
||||
The `@` symbol before the method name identifies `Component` as a decoration.
|
||||
A "decoration" is a TypeScript language feature
|
||||
for creating metadata about the class. Angular finds this metadata
|
||||
in the transpiled JavaScript and responds appropriately.
|
||||
:markdown
|
||||
`@Component` tells Angular that this class *is an Angular component*.
|
||||
The configuration object passed to the `@Component` method has two
|
||||
field, a `selector` and a `template`.
|
||||
|
||||
p.
|
||||
The component controller is the backing of the component's template. This component
|
||||
controller uses TypeScript <code>class</code> syntax.
|
||||
The `selector` specifies a CSS selector for a host HTML element named `my-app`.
|
||||
Angular creates and displays an instance of our `AppComponent`
|
||||
wherever it encounters a `my-app` element.
|
||||
|
||||
code-example(language="javascript" format="linenums").
|
||||
class MyAppComponent {
|
||||
name: string;
|
||||
constructor() {
|
||||
this.name = 'Alice';
|
||||
}
|
||||
}
|
||||
The `template` field is the component's companion template
|
||||
that tells Angular how to render a view.
|
||||
Our template is a single line of HTML announcing "My First Angular App".
|
||||
|
||||
p.
|
||||
Templates read from their component controllers. Templates have access to any properties
|
||||
or functions placed on the component controller.
|
||||
The `bootstrap` method tells Angular to start the application with this
|
||||
component at the application root.
|
||||
We'd be correct to guess that someday our application will
|
||||
consist of more components arising in tree-like fashion from this root.
|
||||
|
||||
p.
|
||||
The template above binds to a <code>name</code> property through
|
||||
the double-mustache syntax (<code ng-non-bindable>{{ ... }}</code>).
|
||||
The body of the constructor assigns "Alice" to the name property. When the
|
||||
template renders, "Hello Alice" appears instead of
|
||||
<span ng-non-bindable>"Hello {{ name }}"</span>.
|
||||
In the top line we imported the `Component`, `View`, and `bootstrap` methods
|
||||
from the Angular 2 library. That's the way we do things now.
|
||||
We no longer expect to find our code or any library code in a global namespace.
|
||||
We `import` exactly what we need, as we need it, from named file and library resources.
|
||||
|
||||
## Add `index.html`
|
||||
|
||||
**Create** an `index.html` file.
|
||||
|
||||
// STEP 5 - Bootstrap ##########################
|
||||
.l-main-section
|
||||
h2#section-transpile 5. Bootstrap
|
||||
**Paste** the following lines into it ... and we'll discuss them:
|
||||
|
||||
p.
|
||||
At the bottom of <code>app.ts</code>, call the <code>bootstrap()</code> function
|
||||
to load your new component into its page:
|
||||
+makeExample('gettingstarted/ts/src/index.1.html', null, 'index.html')
|
||||
|
||||
code-example(language="javaScript").
|
||||
bootstrap(MyAppComponent);
|
||||
:markdown
|
||||
We see three noteworthy sections of HTML:
|
||||
|
||||
1. We load JavaScript libraries from the web.
|
||||
Let's take them on faith without further discussion.<br/><br/>
|
||||
|
||||
p.
|
||||
The <code>bootstrap()</code> function takes a
|
||||
component as a parameter, enabling the component
|
||||
(as well as any child components it contains) to render.
|
||||
2. We configure something called `System` and ask it to import the
|
||||
application file with our `AppComponent` that we just wrote.
|
||||
`System` is the module loader (from the `system.js` library),
|
||||
a tool that can `import` code;
|
||||
remember the `import` statement in our `AppComponent`?
|
||||
|
||||
We're also asking `system.js` to "transpile" (AKA "compile") our
|
||||
TypeScript source code into JavaScript ... right here in the browser.<br/><br/>
|
||||
|
||||
// STEP 6 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
3. We note the `<my-app>` tag in the `<body>`.
|
||||
That's the custom HTML element we identified in the `@Component` decoration
|
||||
adorning our `AppComponent` class.
|
||||
|
||||
h2#section-angular-create-account 6. Declare the HTML
|
||||
## Run it!
|
||||
|
||||
p.
|
||||
Inside the <code>head</code> tag of <code>index.html</code>,
|
||||
include the traceur-runtime and the Angular bundle.
|
||||
Instantiate the <code>my-app</code> component in the <code>body</code>.
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<!-- index.html -->
|
||||
<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://code.angularjs.org/2.0.0-alpha.28/angular2.dev.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- The app component created in app.ts -->
|
||||
<my-app></my-app>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
// STEP 7 - Declare the HTML ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 7. Load the component
|
||||
|
||||
p.
|
||||
The last step is to load the module for the <code>my-app</code> component.
|
||||
To do this, we'll use the System library.
|
||||
We need a static file server to serve our application to the browser.
|
||||
|
||||
.l-sub-section
|
||||
h3 System.js
|
||||
:markdown
|
||||
Don't have a static file server handy? Let's install one of our favorites
|
||||
called [live-server](https://www.npmjs.com/package/live-server "Live-server")
|
||||
with the **npm package manager**.
|
||||
|
||||
Don't have npm?
|
||||
[Get it now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
|
||||
because we're going to use it now and repeatedly throughout this documentation.
|
||||
|
||||
p.
|
||||
<a href="https://github.com/systemjs/systemjs">System</a> is a third-party open-source library that
|
||||
adds ES6 module loading functionality to browsers.
|
||||
Once you have `npm` installed, open a terminal window and enter
|
||||
|
||||
p.
|
||||
Add the System.js dependency in the <code><head></code> tag, so that
|
||||
it looks like:
|
||||
pre.prettyprint.lang-bash
|
||||
code npm install -g live-server
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<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>
|
||||
</head>
|
||||
:markdown
|
||||
Open a terminal window and enter
|
||||
|
||||
p.
|
||||
Add the following module-loading code:
|
||||
pre.prettyprint.lang-bash
|
||||
code live-server
|
||||
:markdown
|
||||
In a few moments, a browser tab should open and display
|
||||
|
||||
code-example(language="html" format="linenums").
|
||||
<my-app></my-app>
|
||||
<script>System.import('app');</script>
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/getting-started/my-first-app.png' alt="Output of getting started app")
|
||||
|
||||
:markdown
|
||||
Congratulations! We are in business.
|
||||
|
||||
// STEP 8 - Run a local server ##########################
|
||||
.l-main-section
|
||||
|
||||
h2#section-load-component-module 8. Run a local server
|
||||
:markdown
|
||||
## What's wrong with this?
|
||||
|
||||
p Run a local HTTP server, and view <code>index.html</code>.
|
||||
We were up and running in a hurry and we could explore Angular
|
||||
in this manner for quite some time.
|
||||
|
||||
p.
|
||||
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:
|
||||
For a number of reasons this isn't a good approach for building an application.
|
||||
<!-- TODO The formatting here is a little weird. Should improve readability. -->
|
||||
|
||||
code-example.
|
||||
# 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
|
||||
* Transpiling TypeScript in the browser becomes tediously slow when our
|
||||
app grows beyond a few files. We certainly won't do that in production. We should learn to
|
||||
compile locally and push the generated JavaScript to the server. We'll need some tools for that.
|
||||
|
||||
|
||||
// WHAT'S NEXT... ##########################
|
||||
* Downloading JavaScript libraries from the web is OK for demos but
|
||||
it slows our development. Every time our app reloads, it must refetch these libraries.
|
||||
Don't count on browser caching.
|
||||
Our debugging and live-reload techniques will bust the browser cache. Loading libraries
|
||||
from the web also prevents us from developing our application offline or where connectivity is
|
||||
poor. Let's learn to download the libraries to our machine and serve them locally.
|
||||
|
||||
|
||||
* We want our development cycle to be as fast and friction-free as possible.
|
||||
When we change our code, we want to see the results in the browser immediately.
|
||||
We have tools and procedures for that.
|
||||
|
||||
.l-main-section
|
||||
h2#section-transpile Great job! We'll have the next steps out soon.
|
||||
|
||||
:markdown
|
||||
# Upping our game
|
||||
Let's take a few more steps to put our development on a better foundation. We will
|
||||
|
||||
1. Revise the application project structure for future growth
|
||||
1. Install a few tools and packages
|
||||
1. Revise the **`index.html`** to use local library resources
|
||||
1. Compile the TypeScript locally and watch for changes
|
||||
|
||||
Shut down the `live-server` running in the terminal window (Ctrl-C) and proceed as follows.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Revise the application project structure
|
||||
|
||||
At the moment we're dumping everything into the "angular2-getting-started" **root folder**.
|
||||
Not bad when there are only two files. Not good as our application evolves.
|
||||
|
||||
Let's give our project a little structure.
|
||||
|
||||
We'll add a sub-folder - `src` - to hold project source code and a sub-sub-folder - `src/app` -
|
||||
to hold the application source code.
|
||||
|
||||
In OS/X and Linux:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir src/app
|
||||
|
||||
:markdown
|
||||
In Windows:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir src\app
|
||||
|
||||
:markdown
|
||||
**Move `index.html`** into the **`src`** folder.
|
||||
|
||||
**Move `app.ts`** into the **`src/app`** folder.
|
||||
|
||||
Our project folders should look like this.
|
||||
```
|
||||
angular2-getting-started
|
||||
└── src
|
||||
├── app
|
||||
│ └── app.ts
|
||||
└── index.html
|
||||
```
|
||||
|
||||
.l-main-section
|
||||
|
||||
:markdown
|
||||
## Install npm packages locally
|
||||
|
||||
We'll replace the web-based scripts in our `index.html` with
|
||||
scripts resident on our local machine.
|
||||
We get those scripts by installing two runtime `npm` packages into our project.
|
||||
|
||||
>**angular2** - the Angular 2 library.
|
||||
|
||||
>**systemjs** - an open-source library that provides module loading.
|
||||
|
||||
We'll also install two development tools:
|
||||
|
||||
>**typescript** - the TypeScript compiler
|
||||
|
||||
>**[live-server](https://www.npmjs.com/package/live-server "Live-server")** - the static file server that reloads the browser when files change.
|
||||
We may have loaded it earlier. We're doing it again
|
||||
locally in our project so we are no longer vulnerable to
|
||||
a global uninstall or version change.
|
||||
|
||||
**Open** a terminal window at our application's **root folder**
|
||||
|
||||
Enter these commands:
|
||||
```
|
||||
npm init -y
|
||||
npm i angular2@2.0.0-alpha.42 systemjs@0.19.2 --save --save-exact
|
||||
npm i typescript live-server --save-dev
|
||||
```
|
||||
|
||||
These commands both *install* the packages and *create* an npm `package.json` that will
|
||||
help us develop and maintain our application in future.
|
||||
The essence of our `package.json` should look like this:
|
||||
|
||||
+makeJson('gettingstarted/ts/package.json', { paths: 'name, version, dependencies, devDependencies'})
|
||||
|
||||
:markdown
|
||||
There is also a `scripts` section. **Find and replace** it with the following:
|
||||
|
||||
+makeJson('gettingstarted/ts/package.json', { paths: 'scripts'})
|
||||
|
||||
:markdown
|
||||
We've just extended our project world with script commands
|
||||
that we'll be running very soon.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Update `index.html`
|
||||
|
||||
**Replace** the library scripts section with references to
|
||||
scripts in the packages we just installed.
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', 'libraries')
|
||||
|
||||
:markdown
|
||||
**Update** the `System` configuration script as follows.
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', 'systemjs')
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
We won't be transpiling TypeScript in the browser anymore.
|
||||
We'll do that on our machine and ship the generated JavaScript
|
||||
files to the server.
|
||||
|
||||
We have to re-configure `system.js` to expect JavaScript files
|
||||
with a `.js` extension by default.
|
||||
Someday we might add a `Foo` class to our application in a `foo.ts`
|
||||
file and import it like this
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code import {Foo} from './app/foo'
|
||||
:markdown
|
||||
`system.js`will know to look for a file named `foo.js` in the `src/app` folder.
|
||||
|
||||
That's exactly what we're doing in the last line. We're
|
||||
importing our main application file `app` (the generated `app.js` to be precise)
|
||||
from the `src/app/` folder (we moved it there, remember?)
|
||||
:markdown
|
||||
Here's the final version
|
||||
|
||||
+makeExample('gettingstarted/ts/src/index.html', null, 'index.html')
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Prepare for TypeScript Compilation
|
||||
|
||||
### Add the TypeScript configuration file
|
||||
|
||||
We'll add a configuration file named **`tsconfig.json`**
|
||||
to tell the editor how to interpret our TypeScript code and
|
||||
to simplify the TypeScript compilation command that we'll run very soon.
|
||||
|
||||
**Change to the `src` folder and create a `tsconfig.json`** file with the following content:
|
||||
+makeJson('gettingstarted/ts/src/tsconfig.json', null, 'tsconfig.json')
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
See the [TypeScript configuration appendix](#tsconfig) to learn more about
|
||||
this file and these settings.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Final structure
|
||||
Our final project folder structure should look like this:
|
||||
```
|
||||
angular2-getting-started
|
||||
├── node_modules
|
||||
├── src
|
||||
│ ├── app
|
||||
| │ └── app.ts
|
||||
│ ├── index.html
|
||||
│ └── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Compile the TypeScript to JavaScript
|
||||
|
||||
We no longer transpile TypeScript to JavaScript in the browser.
|
||||
We run the **T**ype**S**cript **C**ompiler (TSC) on our machine instead.
|
||||
|
||||
Open a terminal window in the **root of the application folder** and enter:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
:markdown
|
||||
When it's done 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.
|
||||
|
||||
Our script set the compiler watch option (`-w`) so the
|
||||
compiler stays alive when it's finished.
|
||||
It watches for changes to our **`.ts`** files
|
||||
and recompiles them automatically.
|
||||
|
||||
Leave this command running in the terminal window.
|
||||
You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## Run the app!
|
||||
|
||||
Now we are ready to see our app in action.
|
||||
|
||||
Open another terminal window in the **root of the application folder** and
|
||||
launch `live-server` again although this time we'll do it with
|
||||
one of our `npm` script commands:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
**live-server** loads the browser for us, serves the HTML and JavaScript files,
|
||||
and displays our application message once more:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/getting-started/my-first-app.png' alt="Output of getting started app")
|
||||
|
||||
:markdown
|
||||
### Make some changes
|
||||
**`live-server`** detects changes to our files and refreshes the browser page for us automatically.
|
||||
|
||||
Try changing the message to "My SECOND Angular 2 app".
|
||||
|
||||
The TypeScript compiler 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.
|
||||
|
||||
Keep `live-server` running in this terminal window. You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
## What have we done?
|
||||
Our first application doesn't do much. It's basically "Hello, World" for Angular 2.
|
||||
|
||||
We kept it simple in our first pass: we wrote a little Angular component,
|
||||
we added some JavaScript libraries to `index.html`, and launched with a
|
||||
static file server. That's about all we'd expect to do for a "Hello, World" app.
|
||||
|
||||
**We have greater ambitions.**
|
||||
|
||||
We won't ask Angular to build "Hello, World".
|
||||
We are asking it to help us build sophisticated applications with sophisticated requirements.
|
||||
|
||||
So we made some strategic technology investments to reach our larger goals
|
||||
|
||||
* our application loads faster with libraries installed locally and
|
||||
we can develop offline if we wish.
|
||||
|
||||
* we're pre-compiling our TypeScript.
|
||||
|
||||
* we're running the compiler and live-server with commands that give us immediate feedback as we make changes.
|
||||
|
||||
The good news is that the overhead of setup is (mostly) behind us.
|
||||
We're about to build a small application that demonstrates the great things
|
||||
we can build with Angular 2.
|
||||
|
||||
<!--TODO: Join us on the [Tour of Heroes](./toh-pt1) -->
|
||||
|
||||
|
||||
<!-- Move this to the Style Guide when we have one -->
|
||||
.l-main-section
|
||||
:markdown
|
||||
<a id="tsconfig"></a>
|
||||
### Appendix: TypeScript configuration
|
||||
We added a TypeScript configuration file (`tsconfig.js`) to our project to
|
||||
guide the compiler as it generates JavaScript files.
|
||||
Get details about `tsconfig.js` from the official
|
||||
[TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json).
|
||||
|
||||
We'd like a moment to discuss the `noImplicitAny` flag.
|
||||
TypeScript developers disagree about whether it should be `true` or `false`.
|
||||
There is no correct answer and we can change the flag later.
|
||||
But our choice now can make a difference in larger projects so it merits
|
||||
discussion.
|
||||
|
||||
When the `noImplicitAny` flag is `false`,
|
||||
the compiler silently defaults the type of a variable to `any` if it cannot infer
|
||||
the type based on how the variable is used. That's what we mean by "implicitly `any`".
|
||||
|
||||
When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer
|
||||
the type, it still generates the JavaScript files but
|
||||
it also reports an error.
|
||||
|
||||
For this project and the other examples in this Developer Guide
|
||||
we set the `noImplicitAny` flag to `false`.
|
||||
Developers who prefer stricter type checking should set the `noImplicitAny` flag to `true`.
|
||||
We can still set a variable's type to `any` if
|
||||
that seems like the best choice. We'd be doing so explicitly after
|
||||
giving the matter some thought.
|
||||
|
||||
If we set the `noImplicitAny` flag to `true`, we may get implicit index errors as well.
|
||||
If we feel these are more annoying than helpful,
|
||||
we can suppress them with the following additional flag.
|
||||
```
|
||||
"suppressImplicitAnyIndexErrors":true
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue