docs(quickstart): quickstart revised with verbose mode toggle button

This commit is contained in:
Ward Bell 2016-02-12 17:54:22 -08:00
parent ad7f172ea5
commit d59b05adde
7 changed files with 595 additions and 574 deletions

View File

@ -46,7 +46,64 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns)
else
!= styleString(jsonExtract, stylePatterns)
- // Open (and close) an explanation <div>. See QuickStart
script.
function why(id, backTo) {
var id = "#"+id;
var el = document.querySelector(id);
el.hidden=el.hidden=!el.hidden;
if (el.hidden && backTo){
// the next line is required to work around a bug in WebKit (Chrome / Safari)
location.href = "#";
location.href = "#" + backTo;
}
}
script.
function verbose(isVerbose) {
isVerbose = !! isVerbose;
var el = document.querySelector('button.verbose.off');
el.style.display = isVerbose ? 'block' : 'none';
var el = document.querySelector('button.verbose.on');
el.style.display = isVerbose ? 'none' : 'block';
CCSStylesheetRuleStyle('main','.l-verbose-section', 'display',
isVerbose ? 'block' : 'none');
}
script.
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
/* returns the value of the element style of the rule in the stylesheet
* If no value is given, reads the value
* If value is given, the value is changed and returned
* If '' (empty string) is given, erases the value.
* The browser will apply the default one
*
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
* string style: camelCase element style, e.g. 'fontSize'
* string value optional : the new value
*/
var CCSstyle = undefined, rules, sheet;
for(var m in document.styleSheets){
sheet = document.styleSheets[m];
if(sheet.href && sheet.href.indexOf(stylesheet) != -1){
rules = sheet[document.all ? 'rules' : 'cssRules'];
for(var n in rules){
console.log(rules[n].selectorText);
if(rules[n].selectorText == selectorText){
CCSstyle = rules[n].style;
break;
}
}
break;
}
}
if(value == undefined)
return CCSstyle[style]
else
return CCSstyle[style] = value
}
//---------------------------------------------------------------------------------------------------------
- var translatePath = function(filePath, region) {
- filePath = filePath.trim();
@ -134,6 +191,7 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns)
- return source;
- }
- var getFragFilePath = function (filePath, region) {
- filePath = filePath.trim();
- var extn = getExtn(filePath);

View File

@ -36,7 +36,6 @@
.then(null, console.error.bind(console));
</script>
<!-- #enddocregion systemjs -->
</head>
<!-- 3. Display the application -->
@ -45,5 +44,4 @@
<my-app>Loading...</my-app>
</body>
<!-- #enddocregion my-app -->
</html>

View File

@ -81,7 +81,7 @@ nav a.router-link-active {
left: .1em;
}
.items li.selected:hover {
background-color: #BBD8DC !important;
background-color: #BBD8DC;
color: white;
}
.items .text {

View File

@ -78,6 +78,11 @@
"intro": "Angular 1 applications can be incrementally upgraded to Angular 2."
},
"typescript-configuration": {
"title": "TypeScript Configuration",
"intro": "TypeScript configuration for Angular 2 developers"
},
"glossary": {
"title": "Glossary",
"intro": "Brief definitions of the most important words in the Angular 2 vocabulary"

View File

@ -0,0 +1,151 @@
include ../../../../_includes/_util-fns
:marked
TypeScript is a primary language for Angular application development.
TypeScript is a dialect of JavaScript with design-time support for type-safety and tooling.
Browsers can't execute TypeScript directly. It has to be "transpiled" into JavaScript with the *tsc* compiler
and that effort requires some configuration.
This chapter covers some aspects of TypeScript configuration and the TypeScript environment
that are important to Angular developers.
a(id="tsconfig")
.l-main-section
:marked
## *tsconfig.json*
We typically add a TypeScript configuration file (`tsconfig.json`) to our project to
guide the compiler as it generates JavaScript files.
.l-sub-section
:marked
Get details about `tsconfig.json` from the official
[TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json).
:marked
We created the following `tsconfig.json` for the [QuickStart](../quickstart.html):
+makeJson('quickstart/ts/tsconfig.1.json', null, 'tsconfig.json')(format=".")
:marked
The options and flags in this file are essential for Angular 2 applications.
<a id="noImplicitAny"></a>
### *noImplicitAny* and *suppressImplicitAnyIndexErrors*
TypeScript developers disagree about whether the `noImplicitAny` flag 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 default),
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 *implicit `any`*.
We initialized the `noImplicitAny` flag to `false` in the QuickStart
to make learning TypeScript development easier.
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**.
Many seasoned developers prefer this stricter setting because type checking catches more
unintentional errors at compile time.
We can set a variable's type to `any` even when the `noImplicitAny` flag is `true`.
We do so when that seems like the best choice for the situation,
deliberately and explicitly, after giving the matter some thought.
If we set the `noImplicitAny` flag to `true`, we may get *implicit index errors* as well.
Most developers feel that *this particular error* is more annoying than helpful.
We can suppress them with the following additional flag.
code-example(format=".").
"suppressImplicitAnyIndexErrors":true
a(id="typings")
.l-main-section
:marked
## TypeScript Typings
Many JavaScript libraries such as jQuery, the Jasmine testing library, and Angular itself,
extend the JavaScript environment with features and syntax
that the TypeScript compiler doesn't recognize natively.
When the compiler doesn't recognize something, it throws an error.
We use [TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files)
&mdash; *d.ts files* &mdash; to tell the compiler about the libraries we load.
TypeScript-aware editors leverage these same definition files to display type information about library features.
Many libraries include their definition files in their npm packages where both the TypeScript compiler and editors
can find them. Angular is one such library.
Peek into the `node_modules/angular2/` folder of any Angular application to see several `...d.ts` files that describe parts of Angular.
**We do nothing to get *typings* files for library packages with bundled *d.ts* files.**
### Manual typings
Sadly, many libraries &mdash; jQuery, Jasmine, and Lodash among them &mdash; do *not* include `d.ts` files in their npm packages.
Fortunately, either their authors or community contributors have created separate *d.ts* files for these libraries and
published them in well-known locations.
The *typings* tool can find and fetch these files for us.
We installed the [typings](https://github.com/typings/typings/blob/master/README.md) tool
with npm (it's listed among the *devDependencies* in the `package.json`) and added an npm script
to run that tool automatically after *npm* installation completes.
+makeJson('quickstart/ts/package.1.json', {paths: 'scripts.postinstall'}, 'package.json (postinstall)')(format=".")
:marked
This *typings* tool command installs the *d.ts* files that we identify in a `typings.json` file
such as this one from the [QuickStart](../quickstart.html):
+makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".")
:marked
We identified only one *typings* file in the QuickStart, the *d.ts* file for
[es6-shim](https://github.com/paulmillr/es6-shim/blob/master/README.md) that brings ES2015/ES6
capabilities to our ES5 browsers.
QuickStart itself doesn't need this shim but many of the documentation samples do
and most of us would be disappointed if typical ES2015 features didn't work out-of-the-box.
We can also run the *typings* tool ourselves. The following command lists the locally installed typings files.
code-example(format="").
npm run typings -- list
:marked
The following command installs the typings file for the Jasmine test library and updates the `typings.config`
so we that we get it automatically the next time.
code-example(format="").
npm run typings -- install jasmine --ambient --save
.l-sub-section
:marked
The [&ndash;&ndash; option](https://docs.npmjs.com/cli/run-script) is important;
it tells npm to pass all arguments to the right of `--` to the *typings* command.
Learn about the features of the *typings* tool at its [site on github](https://github.com/typings/typings/blob/master/README.md).
:marked
#### Typing file collisions
The TypeScript compiler does not tolerate redefinition of a type. For example, it throws an error if it's given two definitions for
the `Promise` type.
Double definitions are common. In fact, the `typings` tool deliberately creates
duplicate sets of typings (for reasons best explained elsewhere).
Look in the project structure for the *typings folder* where we should find something like:
.filetree
.file typings
.children
.file browser
.children
.file ambient
.children
.file es6-shim
.children
.file es6-shim.d.ts
.children
.file main
.children
.file ambient
.children
.file es6-shim
.children
.file es6-shim.d.ts
.children
.file browser.d.ts
.file main.d.ts
:marked
The `es6-shim` typings are duplicated and the `browser.d.ts` and `main.d.ts` have overlapping content.
We must tell the compiler to ignore one or the other.
We removed the `main` set from consideration in the `exclude` section of our `tsconfig.json` file:
+makeJson('quickstart/ts/tsconfig.1.json', {paths: 'exclude'}, 'tsconfig.json (exclude)')(format=".")
:marked

View File

@ -1,270 +1,431 @@
include ../../../_includes/_util-fns
:marked
Let's start from zero and build a super simple Angular 2 application in TypeScript.
Our QuickStart goal is to build and run a super-simple Angular 2 application in TypeScript.
.callout.is-helpful
header Don't want TypeScript?
:marked
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
:marked
## See It Run!
Running the [live example](/resources/live-examples/quickstart/ts/plnkr.html)
is the quickest way to see an Angular 2 app come to life.
Clicking that link fires up a browser, loads the sample in [plunker](http://plnkr.co/ "Plunker"),
Try this <a href="/resources/live-examples/quickstart/ts/plnkr.html" target="_blank">live example</a>
which loads the sample app in <a href="http://plnkr.co/" title="Plunker" target="_blank">plunker</a>
and displays a simple message:
figure.image-display
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app")
:marked
Here is the file structure:
.filetree
.file angular2-quickstart
.children
.file app
.children
.file app.component.ts
.file main.ts
.file index.html
.file license.md
:marked
Functionally, it's an `index.html` and two TypeScript files in an `app/` folder.
We can handle that!
Of course we don't build apps to run in plunker.
The following steps establish a development environment for the documentation samples
that also can be the foundation for our real world applications. At a high level, we will
Of course we won't build many apps that only run in plunker.
Let's follow a process that's closer to what we'd do in real life.
1. Set up our development environment
1. Write the Angular root component for our app
1. Bootstrap it to take control of the main web page
1. Write the main page (`index.html`)
- set up the [development environment](#devenv)
- write the app's Angular [root component](#component)
- write [main.ts](#main) which tells Angular to display the root component
- write the [host web page](#index) (`index.html`)
.l-sub-section
:marked
We really can build the QuickStart from scratch in five minutes
if we follow the instructions and ignore the commentary.
We'll see many code blocks as we pursue this agenda. They're all easy to copy and paste:
code-example(format='.', language='html').
Click the glyph on the right to copy code snippets to the clipboard ⇨⇨⇨⇨⇨⇨⇨⇨⇨⇨
Most of us will be interested in the "why" as well as the "how" and that will take longer.
:marked
button(class="verbose off md-primary md-button md-ink-ripple", type="button", onclick="verbose(false)").
Hide explanations
button(class="verbose on md-primary md-button md-ink-ripple", type="button", onclick="verbose(true)").
View explanations
.l-verbose-section
:marked
*Explanations* describe the concepts and reasons behind the instructions.
Explanations have a thin border on the left like *this* block of text.
Click *Hide Explanations* to show only the instructions.
Click it again to see everything again.
a(id="devenv")
.l-main-section
:marked
## Development Environment
We'll need a place to stand (the application project folder),
some TypeScript configuration, and some libraries for development and runtime.
### Create a new project folder
We need to set up our development environment with
* an [application project folder](#app-folder)
* a [tsconfig.json](#tsconfig) to guide the TypeScript compiler
* a [typings.json](#typings) to install TypeScript definition files
* a [package.json](#package-json) to install *npm* packages with scripts and other assets our app will need.
a(id="app-folder")
:marked
Create a **new project folder**
code-example(format="").
mkdir angular2-quickstart
cd angular2-quickstart
a(id="tsconfig")
:marked
### Configure TypeScript
We must guide the TypeScript compiler with very specific settings.
Add a **tsconfig.json** file to the project folder and copy/paste the following:
+makeJson('quickstart/ts/tsconfig.1.json', null, 'tsconfig.json')(format=".")
.l-sub-section
:marked
We explore the `tsconfig.json` in an [appendix below](#tsconfig)
:marked
### TypeScript Typings
Many JavaScript libraries extend the JavaScript environment with features and syntax
that the TypeScript compiler doesn't recognize natively. We teach it about these capabilities with
[TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files)
&mdash; *d.ts files* &mdash; which we identify in a `typings.json` file.
This `tsconfig.json` file guides the TypeScript compiler.
Learn more about it in the
<a href="guide/typescript-configuration.html#tsconfig" target="_blank">TypeScript Configuration</a> chapter.
a(id="typings")
:marked
Add a **typings.json** file to the project folder and copy/paste the following:
+makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".")
.l-sub-section
:marked
We go a little deeper into *typings* in an [appendix below](#typings)
:marked
### Add the libraries we need
We recommend the **npm** package manager for acquiring and managing our development libraries.
.l-sub-section
.l-verbose-section
:marked
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.
Many JavaScript libraries extend the JavaScript environment with features and syntax
that the TypeScript compiler doesn't recognize natively. We teach it about these capabilities with
<a href="http://www.typescriptlang.org/Handbook#writing-dts-files" target="_blank">TypeScript type definition files</a>
&mdash; *d.ts files* &mdash; which we identify in a `typings.json` file.
We go a little deeper into *typings* in the
<a href="guide/typescript-configuration.html#typings" target="_blank">TypeScript Configuration</a> chapter.
a(id="package-json")
:marked
Add a **package.json** file to the project folder and copy/paste the following:
+makeJson('quickstart/ts/package.1.json', null, 'package.json')(format=".")
.l-sub-section
:marked
Itching to know the details? We explain in the [appendix below](#package-json)
:marked
Install these packages. Open a terminal window (command window in Windows) and
run this npm command.
**Install these packages** by entering the following *npm* command in a terminal window (command window in Windows):
code-example(format="").
npm install
:marked
.l-sub-section
.alert.is-important
:marked
Scary <span style="color:red; font-weight: bold">error messages in red</span> may appear **during** install.
Ignore them. The install will succeed. See the [appendix below](#npm-errors) for more information.
The install typically recovers from these errors and finishes successfully.
.l-verbose-section(class="l-verbose-inherit")
:marked
#### npm errors and warnings
All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**.
There might be a few `npm WARN` messages along the way &mdash; and that is perfectly fine.
We often see an `npm WARN` message after a series of `gyp ERR!` messages.
Ignore them. A package may try to re-compile itself using `node-gyp`.
If the re-compile fails, the package recovers (typically with a pre-built version)
and everything works.
Just make sure there are no `npm ERR!` messages at the end of `npm install`.
.l-verbose-section
:marked
### Adding the libraries we need with *npm*
Angular application developers rely on the <a href="https://docs.npmjs.com/" target="_blank"><i>npm</i></a>
package manager to acquire the libraries their apps require.
Don't have npm?
<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">Get it now</a>
because we're going to use it now and repeatedly throughout this documentation.
The Angular team recommends the starter-set of packages specified in the `dependencies` and `devDependencies`
sections of this QuickStart
<a href="https://docs.npmjs.com/files/package.json" target="_blank">package.json</a> file.
+makeJson('quickstart/ts/package.1.json',{ paths: 'dependencies, devDependencies'}, 'package.json (dependencies)')(format=".")
:marked
There are other possible package choices.
We're recommending this particular set that we know work well together.
Feel free to make substitutions later to suit your tastes and experience.
A `package.json` has an optional **scripts** section where we can define helpful
commands for development and build tasks.
We've included a number of such scripts in our suggested `package.json`:
+makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".")
:marked
We execute most npm scripts in the following way: `npm run` + *script-name*.
Some commands (such as `start` don't require the `run` keyword).
Here's what these scripts do:
* `npm start` - run the compiler and a server at the same time, both in "watch mode"
* `npm run tsc` - run the TypeScript compiler once
* `npm run tsc:w` - run the TypeScript compiler in watch mode;
the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them.
* `npm run lite` - run the <a href="https://www.npmjs.com/package/lite-server" target="_blank">lite-server</a>,
a light-weight, static file server, written and maintained by
<a href="http://johnpapa.net/" target="_blank">John Papa</a>
with excellent support for Angular apps that use routing.
* `npm run typings` - runs the [*typings* tool](#typings)
* `npm postinstall` - called by *npm* automatically *after* it successfully completes package installation.
This script installs the [TypeScript definition files](#typings) this app requires.
:marked
**We're all set.** Let's write some code.
a(id="component")
.l-main-section
:marked
## Our First Angular Component
Let's create a folder to hold our application and add a super-simple Angular component.
The *Component* is the most fundamental of Angular concepts.
A component manages a view - a piece of the web page where we display information
to the user and respond to user feedback.
Technically, a component is a class that controls a view template.
We'll write a lot of them as we build Angular apps. This is our first attempt
so we'll keep it ridiculously simple.
### Create an application source sub-folder
We like to keep our application code in a sub-folder off the root called `app/`.
Execute the following command in the console window.
**Create an *app* sub-folder** off the root directory and make it the current directory
code-example(format="").
mkdir app
cd app
a(id="app-component")
:marked
### Add the component file
Now add a file named **app.component.ts** and paste the following lines:
**Add a component file** named *app.component.ts* and paste the following lines:
+makeExample('quickstart/ts/app/app.component.ts', null, 'app/app.component.ts')(format=".")
:marked
Let's review this file in detail, starting at the bottom where we define a class.
### The Component class
At the bottom of the file is an empty, do-nothing class named `AppComponent`.
When we're ready to build a substantive application,
we can expand this class with properties and application logic.
Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart.
### Modules
Angular apps are modular. They consist of many files each dedicated to a purpose.
Most application files *export* one thing such as a component.
Our `app.component` file exports the `AppComponent`.
+makeExample('quickstart/ts/app/app.component.ts', 'export', 'app/app.component.ts (export)')(format=".")
:marked
The act of exporting turns the file into a module.
The name of the file (without extension) is usually the name of the module.
Accordingly, '*app.component*' is the name of our first module.
A more sophisticated application would have child components that descended from
`AppComponent` in a visual tree.
A more sophisticated app would have more files and modules, at least as many as it had components.
This Quickstart isn't sophisticated; one component is all we need.
Yet modules play a fundamental organizational role in even this small app.
Modules rely on other modules. In TypeScript Angular apps, when we need something
provided by another module, we import it.
When another module needs to refer to `AppComponent`, it imports the `AppComponent` *symbol* like this:
+makeExample('quickstart/ts/app/main.ts', 'app-component','app/main.ts (import)')(format=".")
:marked
Angular is also modular. It is a collection of library modules.
Each library is itself a module made up of several, related feature modules.
When we need something from Angular, we import it from an Angular library module.
We need something from Angular right now to help us define metadata about our component.
### Component Metadata
A class becomes an Angular component when we give it metadata.
Angular needs the metadata to understand how to construct the view
and how the component interacts with other parts of the application.
We define a component's metadata with the Angular `Component` function.
We access that function by importing it from the primary Angular library,`angular2/core`.
+makeExample('quickstart/ts/app/app.component.ts', 'import', 'app/app.component.ts (import)')(format=".")
:marked
In TypeScript we apply that function to the class as a *decorator*
by prefixing it with the **@** symbol and invoking it
just above the component class:
+makeExample('quickstart/ts/app/app.component.ts', 'metadata', 'app/app.component.ts (metadata)')
:marked
`@Component` tells Angular that this class *is an Angular component*.
The configuration object passed to the `@Component` method has two
fields, a `selector` and a `template`.
The `selector` specifies a simple 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 in the host HTML.
.alert.is-helpful
.l-verbose-section
:marked
Remember the `my-app` selector! We'll need that information when we write our `index.html`
### AppComponent is the root of the application
Every Angular app has at least one root component, conventionally named `AppComponent`,
that hosts the client user experience.
Components are the basic building blocks of Angular applications.
A component controls a portion of the screen &mdash; a *view* &mdash; through its associated template.
This QuickStart has only one, extremely simple component.
But it has the essential structure of every component we'll ever write:
* One or more <a href="javascript: why('component-import')">import</a>
statements to reference the things we need.
* A <a href="javascript: why('decorator')">@Component decorator</a>
that tells Angular what template to use and how to create the component.
* A <a href="javascript: why('class')">component class</a>
that controls the appearance and behavior of a view through its template.
a(id="component-import")
:marked
### Import
Angular apps are modular. They consist of many files each dedicated to a purpose.
Angular itself is modular. It is a collection of library modules
each made up of several, related features that we'll use to build our application.
When we need something from a module, we import it.
Here we import the Angular `Component` decorator function from the
main Angular library module because we need it to define our component.
+makeExample('quickstart/ts/app/app.component.ts', 'import', 'app/app.component.ts (import)')(format=".")
a(id="component-decorator")
:marked
### @Component decorator
`Component` is a **decorator** function that takes a *metadata* object.
The metadata tell Angular how to create and use this component.
We apply this function to the component class
by prefixing the function with the **@** symbol and invoking it with the metadata object.
just above the class:
+makeExample('quickstart/ts/app/app.component.ts', 'metadata', 'app/app.component.ts (metadata)')(format=".")
:marked
This particular metadata object has two fields, a `selector` and a `template`.
The **selector** specifies a simple CSS selector for an HTML element that represents the component.
>The element for this component is named `my-app`.
Angular creates and displays an instance of our `AppComponent`
wherever it encounters a `my-app` element in the host HTML.
The **template** specifies the component's companion template,
written in an enhanced form of HTML that tells Angular how to render this component's view.
>Our template is a single line of HTML announcing "*My First Angular App*".
>A more advanced template could contain data bindings to component properties
and might identify other application components which have their own templates.
These templates might identify yet other components.
In this way an Angular application becomes a tree of components.
a(id="component-class")
:marked
### Component class
At the bottom of the file is an empty, do-nothing class named `AppComponent`.
+makeExample('quickstart/ts/app/app.component.ts', 'export', 'app/app.component.ts (class)')(format=".")
:marked
When we're ready to build a substantive application,
we can expand this class with properties and application logic.
Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart.
We **export** `AppComponent` so that we can **import** it elsewhere in our application,
as we'll see when we create `main.ts`.
a(id="main")
.l-main-section
:marked
The `template` property holds the component's companion template.
A template is a form of HTML that tells Angular how to render a view.
Our template is a single line of HTML announcing "My First Angular App".
Now we need something to tell Angular to load this component.
### Bootstrap it
## Show it with *main.ts*
Now we need something to tell Angular to load the root component
Add a new file , `main.ts`, to the `app/` folder as follows:
+makeExample('quickstart/ts/app/main.ts', null, 'app/main.ts')(format=".")
:marked
We need two things to launch the application:
1. Angular's browser `bootstrap` function
1. The application root component that we just wrote.
We import both. Then we call `bootstrap`, passing in the **root component type**,
`AppComponent`.
.l-sub-section
.l-verbose-section
:marked
Learn why we import `bootstrap` from `angular2/platform/browser`
and why we create a separate *main.ts* file in the [appendix below](#main).
:marked
We've asked Angular to launch the app in a browser with our component at the root.
Where will Angular put it?
We import the two things we need to launch the application:
1. Angular's browser `bootstrap` function
1. The application root component, `AppComponent`.
Then we call `bootstrap` with `AppComponent`.
### Bootstrapping is platform-specific
Notice that we import the `bootstrap` function from `angular2/platform/browser`,
not `angular2/core`.
Bootstrapping isn't core because there isn't a single way to bootstrap the app.
True, most applications that run in a browser call the bootstrap function from
this library.
But it is possible to load a component in a different environment.
We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/).
We might wish to render the first page of our application on the server
to improve launch performance or facilitate
[SEO](http://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf).
These targets require a different kind of bootstrap function that we'd import from a different library.
### Why create a separate ***main.ts*** file?
The *main.ts* file is tiny. This is just a QuickStart.
We could have folded its few lines into the `app.component` file
and spared ourselves some complexity.
We'd rather demonstrate the proper way to structure an Angular application.
App bootstrapping is a separate concern from presenting a view.
Mixing concerns creates difficulties down the road.
We might launch the `AppComponent` in multiple environments with different bootstrappers.
Testing the component is much easier if it doesn't also try to run the entire application.
Let's make the small extra effort to do it *the right way*.
a(id="index")
.l-main-section
:marked
## Add the `index.html`
The `index.html` is the web page that hosts the application
Angular displays our application in a specific location on our `index.html`.
It's time to create that file.
We won't put our `index.html` in the `app/` folder.
We'll locate it **up one level, in the project root folder**.
Navigate to the **project root folder**.
code-example(format="").
cd ..
:marked
Now create the`index.html` file and paste the following lines:
Create an`index.html` file in this root folder and paste the following lines:
+makeExample('quickstart/ts/index.html', null, 'index.html')(format=".")
:marked
There are three noteworthy sections of HTML:
.l-verbose-section
:marked
There are three noteworthy sections of HTML
1. We load the JavaScript libraries we need; learn about them [below](#libraries).
1. The JavaScript [libraries](#libraries)
2. We configure something called `System` and ask it to import the
`main` file we just wrote.
2. Configuration of [SystemJS](#systemjs) where we also import and run the
`main` file that we just wrote.
3. We add the `<my-app>` tag in the `<body>`. **This is where our app lives!**
3. The [&lt;my-app>](#my-app) tag in the `<body>` which is *where our app lives!*
Something has to find and load our application modules. We're using **SystemJS** to do that.
There are other choices and we're not saying SystemJS is the best. We like it and it works.
a(id="libraries")
:marked
### Libraries
We loaded the following scripts
+makeExample('quickstart/ts/index.html', 'libraries', 'index.html')(format=".")
:marked
We began with Internet Explorer polyfills.
IE requires polyfills to run
an application that relies on ES2015 promises and dynamic module loading.
Most applications need those capabilities and most applications
should run in Internet Explorer.
The specifics of SystemJS configuration are out of bounds.
We'll briefly describe this particular configuration in the [appendix below](#systemjs).
Next are the polyfills for Angular2, `angular2-polyfills.js`.
When Angular calls the `bootstrap` function in `main.ts`, it reads the `AppComponent`
metadata, finds the `my-app` selector, locates an element tag named `my-app`,
and loads our application between those tags.
Then the [SystemJS](#systemjs) library for module loading,
followed by the Reactive Extensions RxJS library.
.l-sub-section
:marked
Our QuickStart doesn't use the Reactive Extensions
but any substantial application will want them
when working with observables.
We added the library here in QuickStart so we don't forget later.
:marked
Finally, we loaded the web development version of Angular 2 itself.
We'll make different choices as we gain experience and
become more concerned about production qualities such as
load times and memory footprint.
a(id="systemjs")
:marked
### SystemJS Configuration
The QuickStart uses <a href="https://github.com/systemjs/systemjs" target="_blank">SystemJS</a>
to load application and library modules.
There are alternatives that work just fine including the well-regarded
<a href="https://webpack.github.io/" target="_blank">webpack</a>.
SystemJS happens to be a good choice but we want to be clear that it was a choice and not a preference.
All module loaders require configuration and all loader configuration
becomes complicated rather quickly as soon as the file structure diversifies and
we start thinking about building for production and performance.
We suggest becoming well-versed in the loader of your choice.
Learn more about SystemJS configuration
<a href="https://github.com/systemjs/systemjs/blob/master/docs/config-api.md" target="_blank">here</a>.
With those cautions in mind, what are we doing in this QuickStart configuration?
+makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration)')(format=".")
:marked
The `packages` node tells SystemJS what to do when it sees a request for a
module from the `app/` folder.
Our QuickStart makes such requests when one of its
application TypeScript files has an import statement like this:
+makeExample('quickstart/ts/app/main.ts', 'app-component', 'main.ts (excerpt)')(format=".")
:marked
Notice that the module name (after `from`) does not mention a filename extension.
The `packages:` configuration tells SystemJS to default the extension to 'js', a JavaScript file.
That makes sense because we transpile TypeScript to JavaScript
<i>before</i> running the application</a>.
.l-sub-section
:marked
#### Transpiling in the browser
In the live example on plunker we transpile (AKA compile) to JavaScript in the browser
on the fly. That's fine for a demo. That's not our preference for development or production.
We recommend transpiling (AKA compiling) to JavaScript during a build phase
before running the application for several reasons including:
* We see compiler warnings and errors that are hidden from us in the browser.
* Pre-compilation simpifies the module loading process and
it's much easier to diagnose problem when this is a separate, external step.
* Pre-compilation means a faster user experience because the browser doesn't waste time compiling.
* We iterate development faster because we only re-compile changed files.
We notice the difference as soon as the app grows beyond a handful of files.
* Pre-compilation fits into a continuous integration process of build, test, deploy.
:marked
The `System.import` call tells SystemJS to import the `main` file
(`main.js` ... after transpiling `main.ts`, remember?).
`main` is where we tell Angular to launch the application.
We also catch and log launch errors to the console.
All other modules are loaded upon request
either by an import statement or by Angular itself.
a(id="my-app")
:marked
### *&lt;my-app&gt;*
When Angular calls the `bootstrap` function in `main.ts`, it reads the `AppComponent`
metadata, finds the `my-app` selector, locates an element tag named `my-app`,
and loads our application between those tags.
.l-main-section
:marked
@ -348,377 +509,3 @@ figure.image-display
demonstrates the great things we can build with Angular 2.
Join us on the [Tour of Heroes Tutorial](./tutorial)!
.l-main-section
:marked
## Appendices
The balance of this chapter is a set of appendices that
elaborate on some of the points we covered quickly above.
There is no essential material here. Continued reading is for the curious.
<a id="ie-polyfills"></a>
<a id="es6support"></a>
<a id="libraries"></a>
.l-main-section
:marked
## Appendix: Libraries
We loaded the following scripts
+makeExample('quickstart/ts/index.html', 'libraries', 'index.html')(format=".")
:marked
We began with Internet Explorer polyfills.
IE requires polyfills to run
an application that relies on ES2015 promises and dynamic module loading.
Most applications need those capabilities and most applications
should run in Internet Explorer.
.l-sub-section
:marked
We can substitute the following libraries from a CDN:
+makeExample('router/ts/index.1.html','ie-cdn-polyfills')(format=".")
:marked
Next are the polyfills for Angular2, `angular2-polyfills.js`.
Then the [SystemJS library](#systemjs) for module loading,
followed by the Reactive Extensions RxJS library.
.l-sub-section
:marked
Our QuickStart doesn't use the Reactive Extensions
but any substantial application will want them
when working with observables.
We added the library here in QuickStart so we don't forget later.
:marked
Finally, we loaded the web development version of Angular 2 itself.
We'll make different choices as we gain experience and
become more concerned about production qualities such as
load times and memory footprint.
.l-main-section
:marked
<a id="package-json"></a>
## Appendix: package.json
[npm](https://docs.npmjs.com/) is a popular package manager and Angular application developers rely on it
to acquire and manage the libraries their apps require.
We specify the packages we need in an npm [package.json](https://docs.npmjs.com/files/package.json) file.
The Angular team suggests the packages listed in the `dependencies` and `devDependencies`
sections listed in this file:
+makeJson('quickstart/ts/package.1.json',{ paths: 'dependencies, devDependencies'}, 'package.json (dependencies)')(format=".")
:marked
.l-sub-section
:marked
There are other possible package choices.
We're recommending this particular set that we know work well together.
Play along with us for now.
Feel free to make substitutions later to suit your tastes and experience.
:marked
A `package.json` has an optional **scripts** section where we can define helpful
commands to perform development and build tasks.
We've included a number of such scripts in our suggested `package.json`:
+makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".")
:marked
We've seen how we can run the compiler and a server at the same time with this command:
code-example(format="").
npm start
:marked
We execute npm scripts in that manner: `npm run` + *script-name*. Here's what these scripts do:
* `npm run tsc` - run the TypeScript compiler once
* `npm run tsc:w` - run the TypeScript compiler in watch mode;
the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them.
* `npm run lite` - run the [lite-server](https://www.npmjs.com/package/lite-server),
a light-weight, static file server, written and maintained by [John Papa](http://johnpapa.net/)
with excellent support for Angular apps that use routing.
.l-main-section
:marked
<a id="npm-errors"></a>
## Appendix: Npm errors and warnings
All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**.
There might be a few `npm WARN` messages along the way &mdash; and that is perfectly fine.
We often see an `npm WARN` message after a series of `gyp ERR!` messages.
Ignore them. A package may try to re-compile itself using `node-gyp`.
If the re-compile fails, the package recovers (typically with a pre-built version)
and everything works.
Just make sure there are no `npm ERR!` messages at the very end of `npm install`.
<!-- Move this to the Style Guide when we have one -->
.l-main-section
:marked
<a id="tsconfig"></a>
## Appendix: TypeScript configuration
We added a TypeScript configuration file (`tsconfig.json`) to our project to
guide the compiler as it generates JavaScript files.
Get details about `tsconfig.json` from the official
[TypeScript wiki](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json).
The options and flags in the file we provided are essential.
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.
In this QuickStart and many of the other samples 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
```
<a id="typings"></a>
.l-main-section
:marked
## Appendix: TypeScript Typings
Many libraries such as jQuery, the Jasmine testing library, and Angular itself,
add material to the JavaScript environment that the TypeScript compiler doesn't recognize.
When the compiler doesn't recognize something, it throws an error.
We use [TypeScript type definition files](http://www.typescriptlang.org/Handbook#writing-dts-files)
&mdash; *d.ts files* &mdash; to tell the compiler about the libraries we load.
TypeScript-aware editors leverage these same definition files to display type information about library features.
Many libraries include their definition files in their npm packages where both the TypeScript compiler and editors
can find them. Angular is one such library.
Peek into the `node_modules/angular2/` folder to see several `...d.ts` files that describe parts of Angular.
**We do nothing to get *typings* files for library packages with bundled *d.ts* files.**
Sadly, many libraries &mdash; jQuery, Jasmine, and Lodash among them &mdash; do *not* include `d.ts` files in their npm packages.
Fortunately, either their authors or community contributors have created separate *d.ts* files for these libraries and
published them in well-known locations.
The *typings* tool can find and fetch these files for us.
We installed the [typings](https://github.com/typings/typings/blob/master/README.md) tool
with npm (find it in the `package.json`) and added an npm script
to run that tool automatically after *npm* installation completes.
+makeJson('quickstart/ts/package.1.json', {paths: 'scripts.postinstall'}, 'package.json (postinstall)')(format=".")
:marked
This *typings* tool command installs the *d.ts* files that we identified in `typings.json`:
+makeJson('quickstart/ts/typings.1.json', null, 'typings.json')(format=".")
:marked
We identified only one *typings* file in this QuickStart, the *d.ts* file for
[es6-shim](https://github.com/paulmillr/es6-shim/blob/master/README.md) that brings ES2015/ES6
capabilities to our ES5 browsers.
QuickStart itself doesn't need this shim but many of the documentation samples do
and most of us would be disappointed if typical ES2015 features didn't work out-of-the-box.
We can also run the *typings* tool ourselves. The following command lists the locally installed typings files.
code-example(format="").
npm run typings -- list
:marked
The following command installs the typings file for the Jasmine test library and updates the `typings.config`
so we that we get it automatically the next time.
code-example(format="").
npm run typings -- install jasmine --ambient --save
.l-sub-section
:marked
The [&ndash;&ndash; option](https://docs.npmjs.com/cli/run-script) is important;
it tells npm to pass all arguments to the right of `--` to the *typings* command.
Learn about the features of the *typings* tool at its [site on github](https://github.com/typings/typings/blob/master/README.md).
:marked
#### Typing file collisions
The TypeScript compiler does not tolerate redefinition of a type. For example, it throws an error if it's given two definitions for
the `Promise` type.
Double definitions are common. In fact, the `typings` tool deliberately creates
duplicate sets of typings (for reasons best explained elsewhere).
Look in the project structure for the *typings folder* where we should find something like:
.filetree
.file typings
.children
.file browser
.children
.file ambient
.children
.file es6-shim
.children
.file es6-shim.d.ts
.children
.file main
.children
.file ambient
.children
.file es6-shim
.children
.file es6-shim.d.ts
.children
.file browser.d.ts
.file main.d.ts
:marked
The `es6-shim` typings are duplicated and the `browser.d.ts` and `main.d.ts` have overlapping content.
We must tell the compiler to ignore one or the other.
We removed the `main` set from consideration in the `exclude` section of our `tsconfig.json` file:
+makeJson('quickstart/ts/tsconfig.1.json', {paths: 'exclude'}, 'tsconfig.json (exclude)')(format=".")
:marked
.l-main-section
:marked
<a id="systemjs"></a>
## Appendix: SystemJS Configuration
The QuickStart uses [SystemJS](https://github.com/systemjs/systemjs) to load application
and library modules.
There are alternatives that work just fine including the well-regarded [webpack](https://webpack.github.io/).
SystemJS happens to be a good choice but we want to be clear that it was a choice and not a preference.
All module loaders require configuration and all loader configuration
becomes complicated rather quickly as soon as the file structure diversifies and
we start thinking about building for production and performance.
We suggest becoming well-versed in the loader of your choice.
.l-sub-section
:marked
Learn more about SystemJS configuration [here](https://github.com/systemjs/systemjs/blob/master/docs/config-api.md).
:marked
With those cautions in mind, what are we doing here?
+makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration)')(format=".")
:marked
The `packages` node tells SystemJS what to do when it sees a request for a
module from the `app/` folder.
Our QuickStart makes such requests when one of its
application TypeScript files has an import statement like this:
+makeExample('quickstart/ts/app/main.ts', 'app-component', 'main.ts (excerpt)')(format=".")
:marked
Notice that the module name (after `from`) does not mention a filename extension.
The `packages:` configuration tells SystemJS to default the extension to 'js', a JavaScript file.
That makes sense because we transpile TypeScript to JavaScript
*before* running the application.
.l-sub-section
:marked
In the live example on plunker we transpile (AKA compile) to JavaScript in the browser
on the fly. That's fine for a demo. That's not our preference for development or production.
We recommend transpiling (AKA compiling) to JavaScript during a build phase
before running the application for several reasons including:
* We see compiler warnings and errors that are hidden from us in the browser.
* Pre-compilation simpifies the module loading process and
it's much easier to diagnose problem when this is a separate, external step.
* Pre-compilation means a faster user experience because the browser doesn't waste time compiling.
* We iterate development faster because we only re-compile changed files.
We notice the difference as soon as the app grows beyond a handful of files.
* Pre-compilation fits into a continuous integration process of build, test, deploy.
:marked
The `System.import` call tells SystemJS to import the `main` file
(`main.js` ... after transpiling `main.ts`, remember?).
`main` is where we tell Angular to launch the application.
We also catch and log launch errors to the console.
All other modules are loaded upon request
either by an import statement or by Angular itself.
.l-main-section
:marked
<a id="main"></a>
## Appendix: **main.ts**
### Bootstrapping is platform-specific
We import the `bootstrap` function from `angular2/platform/browser`,
not `angular2/core`. There's a good reason.
We only call "core" those capabilities that are the same across all platform targets.
True, most Angular applications run only in a browser and we'll call the bootstrap function from
this library most of the time. It's pretty "core" if we're always writing for a browser.
But it is possible to load a component in a different enviroment.
We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/).
We might wish to render the first page of our application on the server
to improve launch performance or facilitate
[SEO](http://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf).
These targets require a different kind of bootstrap function that we'd import from a different library.
### Why do we create a separate ***main.ts*** file?
The *main.ts* file is tiny. This is just a QuickStart.
We could have folded its few lines into the `app.component` file
and spared ourselves some complexity.
We didn't for what we believe to be good reasons:
1. Doing it right is easy
1. Testability
1. Reusability
1. Separation of concerns
1. We learned about import and export
### It's easy
Sure it's an extra step and an extra file. How hard is that in the scheme of things?
We'll see that a separate `main.ts` is beneficial for *most* apps
even if it isn't critical for the QuickStart.
Let's develop good habits now while the cost is low.
### Testability
We should be thinking about testability from the beginning
even if we know we'll never test the QuickStart.
It is difficult to unit test a component when there is a call to `bootstrap` in the same file.
As soon as we load the component file to test the component,
the `bootstrap` function tries to load the application in the browser.
It throws an error because we're not expecting to run the entire application,
just test the component.
Relocating the `bootstrap` function to `main.ts` eliminates this spurious error
and leaves us with a clean component module file.
### Reusability
We refactor, rename, and relocate files as our application evolves.
We can't do any of those things while the file calls `bootstrap`.
We can't move it.
We can't reuse the component in another application.
We can't pre-render the component on the server for better performance.
### Separation of concerns
A component's responsibility is to present and manage a view.
Launching the application has nothing to do with view management.
That's a separate concern. The friction we're encountering in testing and reuse
stems from this unnecessary mix of responsibilities.
### Import/Export
While writing a separate `main.ts` file we learned an essential Angular skill:
how to export from one module and import into another.
We'll do a lot of that as we learn more Angular.

View File

@ -139,7 +139,29 @@
}
}
button.verbose {
font-size: ($unit * 3);
@media handheld and (max-width: $phone-breakpoint),
screen and (max-device-width: $phone-breakpoint),
screen and (max-width: $tablet-breakpoint) {
font-size: ($unit * 2);
}
}
button.verbose.on {display: none}
.l-verbose-section {
margin: 0px 0px ($unit * 4) 0px;
padding-left: ($unit * 2);
//background: lighten($light, 5%);
border-left: ($unit / 6) solid $grey;
border-radius: ($unit / 6);
}
.l-verbose-inherit {
margin: 0;
padding: 0;
border-left: 0;
border-radius: 0;
}
/*
* Margins & Padding