diff --git a/package.json b/package.json
index eb3acbc979..8510a163f6 100644
--- a/package.json
+++ b/package.json
@@ -60,5 +60,8 @@
"q": "^1.4.1",
"typescript": "~1.5.3",
"yargs": "^3.23.0"
+ },
+ "dependencies": {
+ "jstransformer-marked": "^1.0.1"
}
}
diff --git a/public/docs/_includes/styleguide/_code-examples.jade b/public/docs/_includes/styleguide/_code-examples.jade
index 33420b9d70..9d3519d4b1 100644
--- a/public/docs/_includes/styleguide/_code-examples.jade
+++ b/public/docs/_includes/styleguide/_code-examples.jade
@@ -11,7 +11,7 @@ include ../../../_includes/_util-fns
.showcase-content
.l-sub-section
- :markdown
+ :marked
### Including a code example from the `_examples` folder
One of the design goals for this documention was that any code samples that appear within the documentation be 'testable'.
@@ -35,7 +35,7 @@ include ../../../_includes/_util-fns
code-example(language="js").
include ../../../../_includes/_util-fns
- :markdown
+ :marked
The syntax for the `makeExample` mixin is:
#### +makeExample(filePath, region, title, stylePattern)
@@ -49,14 +49,14 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js").
+makeExample('styleguide/js/index.html', null, 'index.html')
- :markdown
+ :marked
This will read the *_examples/styleguide/js/index.html* file and include it
with the heading 'index.html'. Note that the file will be properly escaped and
color coded according to the extension on the file ( html in this case).
+makeExample('styleguide/js/index.html', null, 'index.html')
- :markdown
+ :marked
The second parameter with a value of 'null' will be described later in this document.
There is a similar `makeTabs` mixin that provides the same service but for multiple examples
@@ -73,13 +73,13 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js").
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test')
- :markdown
+ :marked
This will create two tabs, each with its own title and appropriately color coded.
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test')
.l-sub-section
- :markdown
+ :marked
### Marking up an example file for use by the `makeExample` and `makeTabs` mixins
At a minimum, marking up an example file simply consists of adding a single comment line to the top of the file
@@ -98,7 +98,7 @@ include ../../../_includes/_util-fns
});
});
- :markdown
+ :marked
If a file only has a single `#docregion` then the entire file AFTER the `#docregion` comment is available for inclusion
via mixin. Portions of the file can be indicated by surrounding an area of the file with
`#docregion` and an `#enddocregion` tags. These regions, each with its own name, may be nested to any level and any regions that are not 'ended' explicitly
@@ -130,7 +130,7 @@ include ../../../_includes/_util-fns
// #enddocregion
// #enddocregion
- :markdown
+ :marked
Multiple `#docregion` tags may be defined on a single line as shown below. In addition, anytime a file contains multiple
`#docregion` tags with the same name they will automatically be combined. Each of the individually tagged sections of the combined document
will be separated from one another by a comment consisting of '. . .'. This default separator, known
@@ -158,7 +158,7 @@ include ../../../_includes/_util-fns
doSomethingInteresting();
// #enddocregion
- :markdown
+ :marked
HTML files can also contain #docregion comments:
code-example(format="linenums" language="html" escape="html").
@@ -168,7 +168,7 @@ include ../../../_includes/_util-fns
...
- :markdown
+ :marked
as can CSS files:
code-example(format="linenums" language="css").
@@ -179,7 +179,7 @@ include ../../../_includes/_util-fns
}
.l-sub-section
- :markdown
+ :marked
### Including a named #docregion via the makeExample or makeTabs mixins.
In order to include just a portion of an example file that has been marked up with a 'named' `#docregion`
@@ -189,14 +189,14 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js").
+makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region")
- :markdown
+ :marked
is a request to include just the `class-w-annotations` region from the `app.js` file in the `_examples/styleguide`
folder and results in the following:
+makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region")
.l-sub-section
- :markdown
+ :marked
### Additional styling
In some cases you may want to add additional styling to an external file after it had been included in the documentation.
@@ -215,7 +215,7 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js" escape="none").
+makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*")/g})
- :markdown
+ :marked
Which will mark all of the quoted contents of each `script` tag within the index.html file in pink.
.alert.is-important.
@@ -224,20 +224,20 @@ include ../../../_includes/_util-fns
+makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*")/g})
- :markdown
+ :marked
A more complicated example might be:
code-example(format="linenums" language="js").
- var stylePattern = { pnk: /script (src=.*")/g, otl: /(\S*my-app.*$)/m };
+makeExample('styleguide/js/index.html', null, 'index.html', stylePattern )
- :markdown
+ :marked
Which applies multiple styles and uses an intermediate javascript object as opposed to a literal.
- var stylePattern = { pnk: /script (src=.*")/g, otl: /(\S*my-app.*$)/m };
+makeExample('styleguide/js/index.html', null, 'index.html', stylePattern )
- :markdown
+ :marked
`makeTabs` support for `stylePatterns` is slightly different from the `makeExample` mixin in that you can also
pass in an array of stylePattern objects where each is paired with its corresponding 'tab'. If only a single stylePattern
object is passed in then it is assumed to apply to all of the tabs.
@@ -250,7 +250,7 @@ include ../../../_includes/_util-fns
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns)
.l-sub-section
- :markdown
+ :marked
### Including a JSON file or just parts of one
To include an '.json' file from somewhere in the `doc\_examples` folder you can use the `makeJson` mixin. The `makeExample`
@@ -277,7 +277,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', null, "Entire package.json file")
- :markdown
+ :marked
A subset of the '.json' file can also be selected.
code-example(format="linenums" language="js").
@@ -285,7 +285,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', { paths: 'version, scripts.tsc, scripts.start '}, "Selected parts of the package.json file" )
- :markdown
+ :marked
Styling selected portions of the json is also supported.
code-example(format="linenums" language="js").
@@ -293,7 +293,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*traceur.*)/, /(\Sangular2.*)/, /(\Ssystem.*)/ ]})
- :markdown
+ :marked
As well as styling across multiple lines.
code-example(format="linenums" language="js").
@@ -304,7 +304,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', {paths: 'name, version, dependencies '}, "Foo", styles )
.l-sub-section
- :markdown
+ :marked
### Inline code and code examples provided directly i.e. not from an example file.
The `makeExample` and `makeTabs` mixins are both both built on top of a custom jade 'style'; `code-example`.
@@ -391,7 +391,7 @@ include ../../../_includes/_util-fns
// TAB 2 CONTENT
.l-sub-section
- :markdown
+ :marked
### Combining makeExample, makeTabs mixins with code-example style attributes
As mentioned above the `makeExample` and `makeTabs` mixins are built on top of the `code-example` style. By default
the mixins automatically determine a language based on the example file's extensions and always include line numbers.
@@ -403,12 +403,12 @@ include ../../../_includes/_util-fns
code-example().
+makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15")
- :markdown
+ :marked
Starts the numbering of the example at line 15.
+makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15")
- :markdown
+ :marked
Or to suppress line numbering completely you can use
code-example().
@@ -417,7 +417,7 @@ include ../../../_includes/_util-fns
+makeExample('styleguide/js/app.js', 'class-w-annotations')(format=".")
.l-sub-section
- :markdown
+ :marked
### Code examples in angular/angular source code
References to embedded example code in the angular/angular source make use of the same mixins as defined above, but with a slightly different
@@ -431,7 +431,7 @@ include ../../../_includes/_util-fns
Example files referenced by inline tags are all assumed to be in the 'modules/angular2' folder in the angular/angular repo.
- :markdown
+ :marked
#### @example inline tag parameters
- *filePath:* path to the example file under the '_examples' folder
- *region:* (optional or null) region from the example file to display
@@ -452,7 +452,7 @@ include ../../../_includes/_util-fns
* {@example core/directives/ng_if_spec.ts foo title='Foo' }
**/
- :markdown
+ :marked
#### @exampleTabs inline tag parameters
- *filePaths:* a comma delimited string of filePaths to example files under the '_examples' folder
- *regions:* (optional or null) region from the example file to display
@@ -469,7 +469,7 @@ include ../../../_includes/_util-fns
**/
.l-sub-section
- :markdown
+ :marked
### Cross references to Developer guide pages in angular/angular source comments.
The '{@linkDevGuide ... }' inline tag is intended to be used to create links from api documentation to dev guide
diff --git a/public/docs/dart/latest/quickstart.jade b/public/docs/dart/latest/quickstart.jade
index 4358382a9c..7d5eee942a 100644
--- a/public/docs/dart/latest/quickstart.jade
+++ b/public/docs/dart/latest/quickstart.jade
@@ -1,11 +1,11 @@
include ../../../_includes/_util-fns
-:markdown
+:marked
Let's start from zero and build a super simple Angular 2 application in Dart.
.callout.is-helpful
header Don't want Dart?
- :markdown
+ :marked
Although we're getting started in Dart, you can also write Angular 2 apps
in TypeScript and JavaScript.
Just select either of those languages from the combo-box in the banner.
@@ -27,7 +27,7 @@ p.
.l-main-section
h2#section-install-angular Set up a new app directory
- :markdown
+ :marked
Create a new directory,
and put a file named `pubspec.yaml` in it.
@@ -73,7 +73,7 @@ p.
+makeExample('quickstart/dart/ex1/web/main.dart', null, 'web/main.dart')
- :markdown
+ :marked
You've just defined an Angular 2 **component**,
one of the most important Angular 2 features.
Components are the primary way to create application views
@@ -121,7 +121,7 @@ p.
+makeExample('quickstart/dart/ex1/web/index.html', null, 'web/index.html')
- :markdown
+ :marked
The `` tag in the `` is
the custom HTML element defined in the Dart file.
@@ -149,7 +149,7 @@ p.
Once the app is running,
you should see My First Angular 2 App in your browser window.
- :markdown
+ :marked
If you don't see that, make sure you've entered all the code correctly
and run `pub get`.
@@ -158,14 +158,14 @@ p.
h2#section-angular-run-app Generate JavaScript
- :markdown
+ :marked
Before you can deploy your app, you need to generate JavaScript files.
Pub build makes that easy.
To improve your app's performance, convert the
HTML file to directly include the generated JavaScript;
one way to do that is with dart_to_js_script_rewriter.
- :markdown
+ :marked
Add the dart_to_js_script_rewriter package to your pubspec,
in both the `dependencies` and `transformers` sections.
diff --git a/public/docs/js/latest/quickstart.jade b/public/docs/js/latest/quickstart.jade
index c54f3322f2..bf7852d4aa 100644
--- a/public/docs/js/latest/quickstart.jade
+++ b/public/docs/js/latest/quickstart.jade
@@ -1,54 +1,54 @@
include ../../../_includes/_util-fns
-:markdown
+:marked
Let's start from zero and build a simple Angular 2 application in JavaScript.
.callout.is-helpful
header Don't want JavaScript?
- :markdown
+ :marked
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
+:marked
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. Bootstrap the app
1. Create an *index.html*
1. Run it
.l-main-section
- :markdown
+ :marked
## Create a project folder
-
+
**Create a new folder** to hold our application project, perhaps like this:
```
mkdir angular2-quickstart
cd angular2-quickstart
```
.l-main-section
- :markdown
+ :marked
## Install essential libraries
We'll use the **npm package manager** to install packages for
- the libraries and development tools we need:
+ the libraries and development tools we need:
>angular2 - the Angular 2 library.
-
- >[live-server](https://www.npmjs.com/package/live-server "Live-server")
+
+ >[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.
+
+ 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.
- .alert.is-helpful
- :markdown
+ .alert.is-helpful
+ :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.
-
- :markdown
+
+ :marked
**Open** a terminal window and enter these commands:
```
npm init -y
@@ -61,24 +61,24 @@ include ../../../_includes/_util-fns
+makeJson('quickstart/js/package.json', { paths: 'name, version, dependencies, devDependencies'})
- :markdown
+ :marked
There is also a `scripts` section. **Find and replace** it with the following:
+makeJson('quickstart/js/package.json', { paths: 'scripts'})
- :markdown
+ :marked
We've just extended our project world with a script command that we'll be running very soon.
.l-main-section
- :markdown
+ :marked
## Our first Angular component
Add a new file called *app.js* and paste the following lines:
+makeExample('quickstart/js/app.js', 'class-w-annotations')
- :markdown
- We're creating a visual component named **`AppComponent`** by chaining the
+ :marked
+ We're creating a visual component named **`AppComponent`** by chaining the
`Component` and `Class` methods that belong to the **global Angular namespace, `ng`**.
```
@@ -88,12 +88,12 @@ include ../../../_includes/_util-fns
```
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".
+ 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.
+ 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.
@@ -101,24 +101,24 @@ include ../../../_includes/_util-fns
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
+ :marked
## 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('quickstart/js/app.js', 'bootstrap')
- :markdown
+ :marked
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
+
+ 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.
@@ -126,22 +126,22 @@ include ../../../_includes/_util-fns
### 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")
+ So we'll surround the code in a simple IIFE
+ ("Immediately Invoked Function Execution")
wrapper.
-
+
Here is the entire file:
+makeExample('quickstart/js/app.js', 'dsl')
-
+
.l-main-section
- :markdown
+ :marked
## Create an *index.html*
**Add a new `index.html`** file to the project folder and enter the following HTML
+makeExample('quickstart/js/index.html', null, 'index.html')(format="")
.l-sub-section
- :markdown
+ :marked
Our app loads two script files in the `` element:
>***angular2.sfx.dev.js***, the Angular 2 development library that puts
@@ -149,15 +149,15 @@ include ../../../_includes/_util-fns
>***app.js***, the application JavaScript we just wrote.
- In the ``, there's an element called ``.
+ In the ``, there's an element called ``.
This is the placeholder for the *root* of the
application. Angular displays our application here.
.l-main-section
- :markdown
+ :marked
## Run it!
- We need a file server to serve the static assets of our application
+ We need a file server to serve the static assets of our application
(*index.html* and *app.js*).
For this example we'll use the **live-server** that we installed with `npm`
@@ -170,27 +170,27 @@ include ../../../_includes/_util-fns
code npm start
.alert.is-helpful
- :markdown
+ :marked
That's the `npm` command we added earlier to the `scripts` section of `package.json`
-
- :markdown
+
+ :marked
**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
figure.image-display
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
- :markdown
+ :marked
### Make some changes
The `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".
+ Try changing the message to "My SECOND Angular 2 app".
The `live-server` sees that change and reloads the browser.
- Keep `live-server` running in this terminal window and keep trying changes.
+ 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.
diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade
index 7732ebb023..853e04cf94 100644
--- a/public/docs/ts/latest/guide/dependency-injection.jade
+++ b/public/docs/ts/latest/guide/dependency-injection.jade
@@ -1,26 +1,26 @@
include ../../../../_includes/_util-fns
-:markdown
+:marked
Dependency Injection is an important application design pattern.
- Angular has its own Dependency Injection framework and
+ Angular has its own Dependency Injection framework and
we really can't build an Angular application without it.
In this chapter we'll learn what Dependency Injection is, why we want it, and how to use it.
.l-main-section
-:markdown
+:marked
## Why Dependency Injection?
-
- Let's start with the following code.
-
+
+ Let's start with the following code.
+
```
class Engine {}
-
+
class Tires {}
-
+
class Car {
private engine: Engine;
private tires: Tires;
-
+
constructor() {
this.engine = new Engine();
this.tires = new Tires();
@@ -29,49 +29,49 @@ include ../../../../_includes/_util-fns
drive() {}
}
```
-
- Our `Car` creates everything it needs inside its constructor.
- What's the problem?
-
+
+ Our `Car` creates everything it needs inside its constructor.
+ What's the problem?
+
The problem is that our `Car` class is brittle, inflexible, and hard to test.
-
+
Our `Car` needs an engine and tires. Instead of asking for them,
the `Car` constructor creates its own copies by "new-ing" them from
the very specific classes, `Engine` and `Tires`.
-
+
What if the `Engine` class evolves and its constructor requires a parameter?
- Our `Car` is broken and stays broken until we rewrite it along the lines of
- `this.engine = new Engine(theNewParameter)`.
+ Our `Car` is broken and stays broken until we rewrite it along the lines of
+ `this.engine = new Engine(theNewParameter)`.
We didn't care about `Engine` constructor parameters when we first wrote `Car`.
- We don't really care about them now.
- But we'll *have* to start caring because
+ We don't really care about them now.
+ But we'll *have* to start caring because
when the definion of `Engine` changes, our `Car` class must change.
That makes `Car` brittle.
-
- What if we want to put a different brand of tires on our `Car`. Too bad.
+
+ What if we want to put a different brand of tires on our `Car`. Too bad.
We're locked into whatever brand the `Tires` class creates. That makes our `Car` inflexible.
-
- Right now each new car gets its own engine. It can't share an engine with other cars.
- While that makes sense for an automobile engine,
+
+ Right now each new car gets its own engine. It can't share an engine with other cars.
+ While that makes sense for an automobile engine,
we can think of other dependencies that should be shared ... like the onboard
wireless connection to the manufacturer's service center. Our `Car` lacks the flexibility
to share services that have been created previously for other consumers.
-
+
When we write tests for our `Car` we're at the mercy of its hidden dependencies.
- Is it even possible to create a new `Engine` in a test environment?
+ Is it even possible to create a new `Engine` in a test environment?
What does `Engine`itself depend upon? What does that dependency depend on?
- Will a new instance of `Engine` make an asynchronous call to the server?
+ Will a new instance of `Engine` make an asynchronous call to the server?
We certainly don't want that going on during our tests.
-
+
What if our `Car` should flash a warning signal when tire pressure is low.
How do we confirm that if actually does flash a warning
if we can't swap in low-pressure tires during the test?
-
- We have no control over the car's hidden dependencies.
+
+ We have no control over the car's hidden dependencies.
When we can't control the dependencies, a class become difficult to test.
-
- How can we make `Car` more robust, more flexible, and more testable?
-
+
+ How can we make `Car` more robust, more flexible, and more testable?
+
That's super easy. We probably already know what to do. We change our `Car` constructor to this:
```
@@ -80,50 +80,50 @@ include ../../../../_includes/_util-fns
this.tires = tires;
}
```
- See what happened? We moved the definition of the dependencies to the constructor.
+ See what happened? We moved the definition of the dependencies to the constructor.
Our `Car` class no longer creates an engine or tires.
It just consumes them.
-
- Now we create a car by passing the engine and tires to the constructor.
+
+ Now we create a car by passing the engine and tires to the constructor.
```
var car = new Car(new Engine(), new Tires());
```
- How cool is that?
+ How cool is that?
The definition of the engine and tire dependencies are decoupled from the `Car` class itself.
We can pass in any kind of engine or tires we like, as long as they
conform to the general API requirements of an engine or tires.
-
+
If someone extends the `Engine` class, that is not `Car`'s problem.
.l-sub-section
- :markdown
+ :marked
The consumer of `Car` has the problem. The consumer must update the car creation code to
something like:
```
var car = new Car(new Engine(theNewParameter), new Tires());
```
- The critical point is this: `Car` itself did not have to change.
+ The critical point is this: `Car` itself did not have to change.
We'll take care of the consumer's problem soon enough.
-
-:markdown
- The `Car` class is much easier to test because we are in complete control
+
+:marked
+ The `Car` class is much easier to test because we are in complete control
of its dependencies.
We can pass mocks to the constructor that do exactly what we want them to do
during each test:
```
var car = new Car(new MockEngine(), new MockLowPressureTires());
```
-
- **We just learned what Dependency Injection is**.
-
+
+ **We just learned what Dependency Injection is**.
+
It's a coding pattern in which a class receives its dependencies from external
sources rather than creating them itself.
-
+
Cool! But what about that poor consumer?
Anyone who wants a `Car` must now
create all three parts: the `Car`, `Engine`, and `Tires`.
The `Car` class shed its problems at the consumer's expense.
We need something that takes care of assembling these parts for us.
-
+
We could write a giant class to do that:
```
class SuperFactory {
@@ -136,14 +136,14 @@ include ../../../../_includes/_util-fns
But maintaining it will be hairy as the application grows.
This `SuperFactory` is going to become a huge spider web of
interdependent factory methods!
-
- Wouldn't it be nice if we could simply list the things we want to build without
+
+ Wouldn't it be nice if we could simply list the things we want to build without
having to define which dependency gets injected into what?
-
+
This is where the Dependency Injection Framework comes into play.
- Imagine the framework had something called an `Injector`.
+ Imagine the framework had something called an `Injector`.
We register some classes with this `Injector` and it figures out how to create them.
-
+
When we need a `Car`, we simply ask the `Injector` to get it for us and we're good to go.
```
function main() {
@@ -153,103 +153,103 @@ include ../../../../_includes/_util-fns
}
```
Everyone wins. The `Car` knows nothing about creating an `Engine` or `Tires`.
- The consumer knows nothing about creating a `Car`.
+ The consumer knows nothing about creating a `Car`.
We don't have a gigantic factory class to maintain.
Both `Car` and consumer simply ask for what they need and the `Injector` delivers.
- This is what a **Dependency InjectionFramework** is all about.
+ This is what a **Dependency InjectionFramework** is all about.
- Now that we know what Dependency Injection is and appreciate its benefits,
+ Now that we know what Dependency Injection is and appreciate its benefits,
let's see how it is implemented in Angular.
.l-main-section
-:markdown
+:marked
## Angular Dependency Injection
-
+
Angular ships with its own Dependency Injection framework. This framework can also be used
- as a standalone module by other applications and frameworks.
-
+ as a standalone module by other applications and frameworks.
+
That sounds nice. What does it do for us when building components in Angular?
- Let's see, one step at a time.
-
- We'll begin with a simplified version of the `HeroesComponent`
+ Let's see, one step at a time.
+
+ We'll begin with a simplified version of the `HeroesComponent`
that we built in the [The Tour of Heroes](../tutorial/).
```
import {Component} from 'angular2/angular2';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
-
+
@Component({
selector: 'my-heroes'
templateUrl: 'app/heroes.component.html'
})
export class HeroesComponent {
-
+
heroes: Hero[] = HEROES;
-
+
}
```
It assigns a list of mocked heroes to its `heroes` property for binding within the template.
- Pretty straight forward.
-
- Those heroes are currently a fixed, in-memory collection, defined in another file and imported by the component.
+ Pretty straight forward.
+
+ Those heroes are currently a fixed, in-memory collection, defined in another file and imported by the component.
That works in the early stages of development but it's far from ideal.
- As soon as we try to test this component or want to get our heroes data from a remote server,
- we'll have to change this component's implementation of `heroes` and
+ As soon as we try to test this component or want to get our heroes data from a remote server,
+ we'll have to change this component's implementation of `heroes` and
fix every other use of the `HEROES` mock data.
-
+
Let's make a service that hides how we get Hero data.
.l-sub-section
- :markdown
+ :marked
Write this service in its own file. See [this note](#forward-ref) to understand why.
-:markdown
+:marked
```
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
-
+
class HeroService {
-
+
heroes: Hero[];
-
+
constructor() {
this.heroes = HEROES;
}
-
+
getHeroes() {
return this.heroes;
}
}
```
- Our `HeroService` exposes a `getHeroes()` method that returns
- the same mock data as before but none of its consumers need to know that.
-
- A service is nothing more than a class in Angular 2.
+ Our `HeroService` exposes a `getHeroes()` method that returns
+ the same mock data as before but none of its consumers need to know that.
+
+ A service is nothing more than a class in Angular 2.
It remains nothing more than a class until we register it with
the Angular injector.
-
+
### Configuring the Injector
-
+
We don't have to create the injector.
Angular creates an application-wide injector for us during the bootstrap process.
```
bootstrap(HeroesComponent);
- ```
-
- Let’s configure the injector at the same time that we bootstrap by adding
- our `HeroService` to an array in the second argument.
+ ```
+
+ Let’s configure the injector at the same time that we bootstrap by adding
+ our `HeroService` to an array in the second argument.
We'll explain that array when we talk about [providers](#providers) later in this chapter.
```
bootstrap(AppComponent, [HeroService]);
- ```
+ ```
That’s it! The injector now knows about the `HeroService` which is available for injection across our entire application.
-
+
### Preparing the `HeroesComponent` for injection
-
+
The `HeroesComponent` should get its heroes from this service.
Per the dependency injection pattern, the component must "ask for" the service in its constructor [as we explained
earlier](#ctor-injection)".
-
+
```
constructor(heroService: HeroService) {
this.heroes = heroService.getHeroes();
@@ -257,19 +257,19 @@ include ../../../../_includes/_util-fns
```
.l-sub-section
- :markdown
+ :marked
Adding a parameter to the constructor isn't all that's happening here.
-
+
We are writing the app in TypeScript and have followed the parameter name with a type notation, `:HeroService`.
The class is also decorated with the `@Component` decorator (scroll up to confirm that fact).
-
+
When the TypeScript compiler evaluates this class, it sees the decorator and adds class metadata
into the generated JavaScript code. Within that metadata lurks the information that
- associates the `heroService` parameter with the `HeroService` class.
-
+ associates the `heroService` parameter with the `HeroService` class.
+
That's how the Angular injector will know to inject an instance of the `HeroService` when it
creates a new `HeroesComponent`.
-:markdown
+:marked
### Creating the `HeroesComponent` with the injector (implicitly)
When we introduced the idea of an injector above, we showed how to create
a new `Car` with that injector.
@@ -281,24 +281,24 @@ include ../../../../_includes/_util-fns
var hc = injector.get(HeroesComponent);
```
We *could* write code like that if we wanted to. We just don't have to.
- Angular does that for us when it renders a `HeroesComponent`
+ Angular does that for us when it renders a `HeroesComponent`
whether we ask for it in an HTML template ...
```
```
... or navigate to a `HeroesComponent` view with the [router](./router.html).
-
- ### Singleton services
- We might wonder what happens when we inject the `HeroService` into other components.
+
+ ### Singleton services
+ We might wonder what happens when we inject the `HeroService` into other components.
Do we get the same instance every time?
-
- Yes we do. Dependencies are singletons.
- We’ll discuss that later in our chapter about
+
+ Yes we do. Dependencies are singletons.
+ We’ll discuss that later in our chapter about
[Hierarchical Injectors](./hierarchical-dependency-injection.html).
### Testing the component
We emphasized earlier that designing a class for dependency injection makes it easier to test.
-
+
Mission accomplished! We don't even need the Angular Dependency Injection system to test the `HeroesComponent`.
We simply create a bew `HeroesComponent` with a mock service and poke at it:
```
@@ -307,28 +307,28 @@ include ../../../../_includes/_util-fns
expect(hc.heroes.length).toEqual(mockService.getHeroes().length);
})
```
- ### When the service needs a service
- Our `HeroService` is very simple. It doesn't have any dependencies of its own.
-
-
+ ### When the service needs a service
+ Our `HeroService` is very simple. It doesn't have any dependencies of its own.
+
+
What if it had a dependency? What if it reported its activities through a logging service?
- We'd apply the same "constructor injection" pattern.
-
+ We'd apply the same "constructor injection" pattern.
+
Here's a rewrite of `HeroService` with a new constructor that takes a `logger` parameter.
```
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
import {Logger} from './logger';
-
+
@Injectable()
class HeroService {
-
+
heroes: Hero[];
-
+
constructor(private logger: Logger) {
this.heroes = HEROES;
}
-
+
getHeroes() {
this.logger.log('Getting heroes ...')
return this.heroes;
@@ -337,74 +337,74 @@ include ../../../../_includes/_util-fns
```
The constructor now asks for an injected instance of a `Logger` and stores it in a private property called `logger`.
We call that property within our `getHeroes()` method when anyone asks for heroes.
-
+
**The `@Injectable()` decoration catches our eye!**
-
+
.alert.is-critical
- :markdown
- **Always include the parentheses!** Always call `@Injectable()`. It's easy to forget the parentheses.
+ :marked
+ **Always include the parentheses!** Always call `@Injectable()`. It's easy to forget the parentheses.
Our application will fail mysteriously if we do. It bears repeating: **always include the parentheses.**
-:markdown
- We haven't seen `@Injectable()` before.
+:marked
+ We haven't seen `@Injectable()` before.
As it happens, we could have added it to `HeroService`. We didn't bother because we didn't need it then.
-
- We need it now ... now that our service has an injected dependency.
- We need it because Angular requires constructor parameter metadata in order to inject a `Logger`.
+
+ We need it now ... now that our service has an injected dependency.
+ We need it because Angular requires constructor parameter metadata in order to inject a `Logger`.
As [we mentioned earlier](#di-metadata), TypeScript *only generates metadata for classes that have a decorator*. .
-
- The `HeroesComponent` has an injected dependency too. Why don't we add `@Injectable()` to the `HeroesComponent`?
+
+ The `HeroesComponent` has an injected dependency too. Why don't we add `@Injectable()` to the `HeroesComponent`?
We *can* add it if we really want to. It isn't necessary because the `HeroesComponent` is already decorated with `@Component`.
TypeScript generates metadata for *any* class with a decorator and *any* decorator will do.
-
+
.l-main-section
-:markdown
+:marked
## Injector Providers
-
- Remember when we added the `HeroService` to an array in the [bootstrap](#bootstrap) process?
+
+ Remember when we added the `HeroService` to an array in the [bootstrap](#bootstrap) process?
```
bootstrap(AppComponent, [HeroService]);
```
- That list of classes is actually a list of **providers**.
-
+ That list of classes is actually a list of **providers**.
+
"Providers" create the instances of the things that we ask the injector to inject.
There are many ways ways to "provide" a thing that has the necessary shape and behavior to serve as a `HeroService`.
A class is a natural provider - it's meant to be created. But it's not the only way
- to produce something injectable. We could hand the injector an object to return. We could give it a factory function to call.
- Any of these approaches might be a good choice under the right circumstances.
-
+ to produce something injectable. We could hand the injector an object to return. We could give it a factory function to call.
+ Any of these approaches might be a good choice under the right circumstances.
+
What matters is that the injector knows what to do when something asks for a `HeroService`.
### The Provider Class
-
+
When we wrote ...
```
[HeroService];
```
- we used a short-hand expression for provider registration.
+ we used a short-hand expression for provider registration.
Angular expanded that short-hand into a call to the Angular `provide` method
```
- [provide(HeroService, {useClass:HeroService})];
+ [provide(HeroService, {useClass:HeroService})];
```
- and the `provide` method in turn creates a new instance of the Angular
+ and the `provide` method in turn creates a new instance of the Angular
[Provider class](http://localhost:3000/docs/ts/latest/api/core/Provider-class.html):
```
[new Provider(HeroService, {useClass:HeroService})]
```
- This provider instance associates a `HeroService` *token*
+ This provider instance associates a `HeroService` *token*
with code that can create an *instance* of a `HeroService`.
The first parameter is the [token](#token) that serves as the key for both locating a dependency value
- and registering the provider.
-
+ and registering the provider.
+
The second parameter is a provider definition object
- which we think of as a "recipe" for creating the dependency value.
+ which we think of as a "recipe" for creating the dependency value.
There are many ways to create dependency values ... and many ways to write a recipe.
-
+
### Alternative Class Providers
Occasionally we'll ask a different class to provide the service.
-
+
We do that regularly when testing a component that we're creating with dependency injection.
In this example, we tell the injector
to return a `MockHeroService` when something asks for the `HeroService`.
@@ -414,42 +414,42 @@ include ../../../../_includes/_util-fns
]);
```
### Value Providers
-
+
Sometimes it's easier to provide a ready-made object rather than ask the injector to create it from a class.
-
+
We do that a lot when we write tests. We might write the following test setup
- for tests that explore how the `HeroComponent` behaves when the `HeroService`
+ for tests that explore how the `HeroComponent` behaves when the `HeroService`
returns an empty hero list.
```
beforeEachProviders(() => {
-
+
let emptyHeroService = { getHeroes: () => [] };
-
+
return [ provide(HeroService, {useValue: emptyHeroService}) ];
});
```
Notice we defined the recipe with `useValue` instead of `useClass`.
-
+
### Factory Providers
-
+
Sometimes the best choice for a provider is neither a class nor a value.
-
+
Suppose our HeroService has some cool new feature that we're only offering to "special" users.
- The HeroService shouldn't know about users and
+ The HeroService shouldn't know about users and
we won't know if the current user is special until runtime anyway.
- We decide to extend our `HeroService` constructor to accept a `useCoolFeature` flag
+ We decide to extend our `HeroService` constructor to accept a `useCoolFeature` flag
that toggles the feature on or off.
We rewrite the `HeroService` again as follows.
```
@Injectable()
class HeroService {
-
+
heroes: Hero[];
-
+
constructor(private logger: Logger, private useCoolFeature: boolean) {
this.heroes = HEROES;
}
-
+
getHeroes() {
let msg = this.useCoolFeature ? 'the cool new way' : 'the old way';
this.logger.log('Getting heroes ...' + msg)
@@ -457,9 +457,9 @@ include ../../../../_includes/_util-fns
}
}
```
- The feature flag is a simple boolean value. We'd like to inject the flag but it seems silly to write an entire class for a
+ The feature flag is a simple boolean value. We'd like to inject the flag but it seems silly to write an entire class for a
simple flag.
-
+
We can replace the `HeroService` provider with a factory function that creates a properly configured `HeroService` for the current user.
We'll' build up to that result, beginning with our definition of the factory function:
```
@@ -468,59 +468,59 @@ include ../../../../_includes/_util-fns
}
```
.l-sub-section
- :markdown
- The factory takes two parameters: the logger service and a user service.
+ :marked
+ The factory takes two parameters: the logger service and a user service.
The logger we pass straight to the constructor as we did before.
-
- We'll know to use the cool new feature if the `userService.user.isSpecial` flag is true,
+
+ We'll know to use the cool new feature if the `userService.user.isSpecial` flag is true,
a fact we can't know until runtime.
-:markdown
- We use dependency injection everywhere so of course the factory function depends on
- two injected services: `Logger` and `UserService`.
+:marked
+ We use dependency injection everywhere so of course the factory function depends on
+ two injected services: `Logger` and `UserService`.
We declare those requirements in our provider definition object:
```
let heroServiceDefinition = {
- useFactory: heroServiceFactory,
+ useFactory: heroServiceFactory,
deps: [Logger, UserService]
};
```
.l-sub-section
- :markdown
+ :marked
The `useFactory` field tells Angular that the provider is a factory function and that its implementation is the `heroServiceFactory`.
-
- The `deps` property is an array of [provider tokens](#token).
+
+ The `deps` property is an array of [provider tokens](#token).
The `Logger` and `UserService` classes serve as tokens for their own class providers.
-:markdown
- Finally, we create the provider and adjust the bootstrapping to include that provider
+:marked
+ Finally, we create the provider and adjust the bootstrapping to include that provider
among its provider registrations.
```
let heroServiceProvider = provide(HeroService, heroServiceDefinition);
-
+
bootstrap(AppComponent, [heroServiceProvider, Logger, UserService]);
```
-
+
### String tokens
-
+
Sometimes we have an object dependency rather than a class dependency.
-
+
Applications often define configuration objects with lots of small facts like the title of the application or the address of a web api endpoint.
These configuration objects aren't always instances of a class. They're just objects ... like this one:
```
let config = {
apiEndpoint: 'api.heroes.com',
title: 'The Hero Employment Agency'
- };
+ };
```
- We'd like to make this `config` object available for injection.
+ We'd like to make this `config` object available for injection.
We know we can register an object with a "Value Provider". But what do we use for the token?
- Until now, we've always asked the class to play the token role
+ Until now, we've always asked the class to play the token role
whether we wrote a provider with a class, value, or factory recipe.
This time we don't have a class to serve as a token. There is no `Config` class.
-
- Fortunately, the token can be a string, a class type, or an
- [OpaqueToken](http://localhost:3000/docs/ts/latest/api/core/OpaqueToken-class.html).
+
+ Fortunately, the token can be a string, a class type, or an
+ [OpaqueToken](http://localhost:3000/docs/ts/latest/api/core/OpaqueToken-class.html).
Internally, the `Provider` turns the string and class parameter into an `OpaqueToken`;
the injector locates dependency values and providers by this token.
@@ -532,7 +532,7 @@ include ../../../../_includes/_util-fns
]);
```
- Let's apply what we've learned and update the `HeroesComponent` constructor so it can display the configured title.
+ Let's apply what we've learned and update the `HeroesComponent` constructor so it can display the configured title.
Right now the constructor signature is
```
constructor(heroService: HeroService)
@@ -546,38 +546,38 @@ include ../../../../_includes/_util-fns
We'll need a little help from another Angular decorator called `@Inject`.
```
import {Inject} from 'angular2/angular2'
-
+
constructor(heroService: HeroService, @Inject('app.config') config)
-
+
```
.l-main-section
-:markdown
+:marked
# Next Steps
We learned the basics of Angular Dependency Injection in this chapter.
-
- The Angular Dependency Injection is more capable than we've described.
+
+ The Angular Dependency Injection is more capable than we've described.
We can learn more about its advanced features, beginning with its support for
- a hierarchy of nested injectors in the next
+ a hierarchy of nested injectors in the next
[Dependency Injection chapter](./hierarchical-dependency-injection.html)
-
+
.l-main-section
-:markdown
+:marked
### Appendix: Why we recommend one class per file
- Developers expect one class per file. Multiple classes per file is confusing and is best avoided.
+ Developers expect one class per file. Multiple classes per file is confusing and is best avoided.
If we define every class in its own file, there is nothing in this note to worry about.
Move along!
-
+
If we scorn this advice
- and we add our `HeroService` class to the `HeroesComponent` file anyway,
- **define the `HeroesComponent` last!**
+ and we add our `HeroService` class to the `HeroesComponent` file anyway,
+ **define the `HeroesComponent` last!**
If we put it define component before the service,
we'll get a runtime null reference error.
To understand why, paste the following incorrect, ultra-simplified rendition of these two
classes into the [TypeScript playground](http://www.typescriptlang.org/Playground).
-
+
```
class HeroesComponent {
static $providers=[HeroService]
@@ -588,18 +588,18 @@ include ../../../../_includes/_util-fns
alert(HeroesComponent.$providers)
```
.l-sub-section
- :markdown
+ :marked
The `HeroService` is incorrectly defined below the `HeroComponent`.
-
+
The `$providers` static property represents the metadata about the injected `HeroService`
that TypeScript compiler would add to the component class.
-
- The `alert` simulates the action of the Dependency Injector at runtime
+
+ The `alert` simulates the action of the Dependency Injector at runtime
when it attempts to create a `HeroesComponent`.
-:markdown
- Run it. The alert appears but displays nothing.
+:marked
+ Run it. The alert appears but displays nothing.
This is the equivalent of the null reference error thrown at runtime.
-
+
We understand why when we review the generated JavaScript which looks like this:
```
var HeroesComponent = (function () {
@@ -608,28 +608,28 @@ include ../../../../_includes/_util-fns
HeroesComponent.$providers = [HeroService];
return HeroesComponent;
})();
-
+
var HeroService = (function () {
function HeroService() {
}
return HeroService;
})();
-
+
alert(HeroesComponent.$providers);
```
- Notice that the TypeScript compiler turns classes into function expressions
+ Notice that the TypeScript compiler turns classes into function expressions
assigned to variables. The value of the captured `HeroService` variable is undefined
when the `$providers` array is assigned. The `HeroService` variable gets its value too late
to be captured.
-
+
Reverse the order of class definition so that the `HeroService`
appears before the `HeroesComponent` that requires it.
Run again. This time the alert displays the `HeroService` function definition.
If we insist on defining the `HeroService` in the same file and insist on
defining the component first, Angular offers a way to make that work.
- The `forwardRef()` method let's us reference a class
- before it has been defined.
+ The `forwardRef()` method let's us reference a class
+ before it has been defined.
Learn more about this problem and the `forwardRef()`
in this [blog post](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html).
diff --git a/public/docs/ts/latest/guide/displaying-data.jade b/public/docs/ts/latest/guide/displaying-data.jade
index 08b686b365..c311e7b26d 100644
--- a/public/docs/ts/latest/guide/displaying-data.jade
+++ b/public/docs/ts/latest/guide/displaying-data.jade
@@ -2,7 +2,7 @@ include ../../../../_includes/_util-fns
-:markdown
+:marked
## Displaying Component Properties
We typically display data in Angular by binding controls in an HTML template
@@ -17,7 +17,7 @@ figure.image-display
img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI")
.l-main-section
-:markdown
+:marked
## Showing component properties with interpolation
The easiest way to display a component property
is to bind the property name through interpolation.
@@ -32,7 +32,7 @@ figure.image-display
+makeExample('displaying-data/ts/src/app/app.1.ts')
-:markdown
+:marked
We added two properties to the formerly empty component: `title` and `myHero`.
Our revised template displays the two component properties using the double curly brace
@@ -40,24 +40,24 @@ figure.image-display
+makeExample('displaying-data/ts/src/app/app.1.ts', 'template')
.l-sub-section
- :markdown
+ :marked
The template is a multi-line string within ECMAScript 2015 back-tics (\`).
The back-tick (\`) is not the same character as a single quote (').
It has many nice features. The feature we're exploiting is
the ability to compose the string over several lines which
makes for much more readable HTML.
-:markdown
+:marked
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
inserts those values into the browser. Angular will update the display
when these properties change.
.l-sub-section
- :markdown
+ :marked
More precisely, the re-display occurs after some kind of asynchronous event related to
the view such as a keystroke, a timer completion, or an asynch `XHR` response.
We don't have those in this sample.
But then the properties aren't changing on their own either. For the moment we must operate on faith.
-:markdown
+:marked
Notice that we haven't called **new** to create an instance of the `AppComponent` class.
Angular is creating an instance for us. How?
@@ -65,7 +65,7 @@ figure.image-display
Remember back in QuickStart that we added the `` element to the body of our `index.html`
+makeExample('displaying-data/ts/src/index.html', 'my-app')
-:markdown
+:marked
When we bootstrap with the `AppComponent` class (see the bottom of `app.ts`), Angular looks for a ``
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
inside the `` tag.
@@ -90,40 +90,40 @@ figure.image-display
Some folks prefer to declare the properties and initialize them within a constructor like this:
+makeExample('displaying-data/ts/src/app/app-ctor.ts', 'app-ctor')
-:markdown
+:marked
That's fine too. The choice between them is a matter of taste and organization policy.
We'll adopt the more terse "variable assignment" style in this chapter simply because
there will be less code to read.
.l-main-section
-:markdown
+:marked
## Showing an array property with NgFor
We want to display a list of heroes. We begin by adding a mock heroes name array to the component,
just above `myHero` and redefine `myHero` to be the first name in the array.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'mock-heroes')
-:markdown
+:marked
Now we use the Angular `NgFor` "repeater" Directive in the template to display
each item in the `heroes` list.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'template')
-:markdown
+:marked
Our presentation is the familiar HTML unordered list with `
` and `
` tags. Let's focus on the `
` tag.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'li-repeater')
-:markdown
+:marked
We added a somewhat mysterious `*ng-for` to the `
` element.
That's the Angular "repeater" directive.
It's presence on the `
` tag marks that `
` element (and its children) as the "repeater template".
.alert.is-important
- :markdown
+ :marked
Don't forget the leading asterisk (\*) in front of `*ng-for`. It is an essential part of the syntax.
Learn more about this and `NgFor` in the [Template Syntax](./template-syntax.html#ng-for) chapter.
-:markdown
+:marked
Notice the `#hero` in the `NgFor` double-quoted instruction.
The `#hero` is a "[template local variable](./template-syntax.html#local-vars")" *declaration*.
The (#) prefix declares a local variable name named `hero`.
@@ -133,11 +133,11 @@ figure.image-display
context for the interpolation in the double curly braces.
.l-sub-section
- :markdown
+ :marked
We happened to give `NgFor` an array to display.
In fact, `NgFor` can repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)
object.
-:markdown
+:marked
## Register the NgFor Directive
Angular doesn't know that this template uses the `NgFor` directive.
@@ -149,20 +149,20 @@ figure.image-display
Look for it in the following:
+makeExample('displaying-data/ts/src/app/app.2.ts', 'imports')
-:markdown
+:marked
Second, we register `NgFor` as a directive accessible to the template by updating the
`@Component` decorator with a `directives` array property whose only item is `NgFor`:
+makeExample('displaying-data/ts/src/app/app.2.ts', 'directives')
-:markdown
+:marked
Now the heroes will appear in the view as an unordered list.
figure.image-display
img(src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor")
.l-main-section
-:markdown
+:marked
## Creating a class for the data
We are defining our data directly inside our component.
@@ -177,7 +177,7 @@ figure.image-display
Create a new file called `hero.ts` and add the following short snippet to it.
+makeExample('displaying-data/ts/src/app/hero.ts')
-:markdown
+:marked
We've defined a class with a constructor and two properties: `id` and `name`.
If we are new to TypeScript, it may not look like we have properties. But we do. We're taking
@@ -186,30 +186,30 @@ figure.image-display
Consider the first parameter:
+makeExample('displaying-data/ts/src/app/hero.ts', 'id-parameter')
-:markdown
+:marked
That brief syntax simultaneously
* declares a constructor parameter and its type
* declare a public property of the same name
* initializes that property with the corresponding argument when we "new" an instance of the class.
.l-main-section
-:markdown
+:marked
## Use the Hero class
Let's redefine the heroes property in our component to return an array of these Heroes
and also set the `myHero` property with the first of these mock heroes.
+makeExample('displaying-data/ts/src/app/app.3.ts', 'heroes')
-:markdown
+:marked
We'll have to update the template.
At the moment it displays the entire hero object which used to be a string value.
Let's fix that so we interpolate the `hero.name` property
+makeExample('displaying-data/ts/src/app/app.3.ts', 'template')
-:markdown
+:marked
Our display looks the same but we know how much better it is under the hood.
.l-main-section
-:markdown
+:marked
## Conditional display with NgIf
Sometimes the app should display a view or a portion of a view only under prescribed circumstances.
@@ -220,38 +220,38 @@ figure.image-display
We can see it in action by adding the following paragraph at the bottom of the template:
+makeExample('displaying-data/ts/src/app/app.final.ts', 'message')
.alert.is-important
- :markdown
+ :marked
Don't forget the leading asterisk (\*) in front of `*ng-if`. It is an essential part of the syntax.
Learn more about this and `NgIf` in the [Template Syntax](./template-syntax.html#ng-if) chapter.
-:markdown
+:marked
The [template expression](./template-syntax.html#template-expressions) inside the double quotes
looks much like JavaScript and it is much like JavaScript.
When the component's list of heroes has more than 3 items, Angular adds the paragraph to the DOM and the message appears.
If there were 3 or fewer items, Angular omits the the paragraph and there is no message.
.alert.is-helpful
- :markdown
+ :marked
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM.
That hardly matters here. It would matter a great deal from a performance perspective if
we were conditionally including or excluding a big chunk of HTML with many data bindings.
-:markdown
+:marked
As with the `NgFor`, we must add the `NgIf` directive to the component's metadata.
We should extend our `import` statement as before ...
+makeExample('displaying-data/ts/src/app/app.3.ts', 'import-ng-if')
-:markdown
+:marked
... and add it to the directives array:
+makeExample('displaying-data/ts/src/app/app.3.ts', 'directives')
-:markdown
+:marked
Try it out. We have four items in the array so the message should appear.
Delete one of the elements from the array, refresh the browser, and the message should no longer appear.
.l-main-section
-:markdown
+:marked
## Use the CORE_DIRECTIVES Constant
There are other core Angular directives, such as `NgClass` and `NgSwitch`,
@@ -266,15 +266,15 @@ figure.image-display
We'll revise our `import` statement one last time.
+makeExample('displaying-data/ts/src/app/app.final.ts', 'imports')
-:markdown
+:marked
and update the `directives` metadata
+makeExample('displaying-data/ts/src/app/app.final.ts', 'directives')
-:markdown
+:marked
Pro tip: we register this constant in almost every template we write.
.l-main-section
-:markdown
+:marked
## Summary
Now we know how to
- use **interpolation** with the double curly braces to display a component property,
@@ -291,7 +291,7 @@ figure.image-display
'app.ts, hero.ts')
.l-main-section
-:markdown
+:marked
## Next Steps
In addition to displaying data, most applications need to respond to user input.
Learn about that in the [User Input](./user-input.html) chapter.
diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade
index ac62010289..3096889cc9 100644
--- a/public/docs/ts/latest/guide/forms.jade
+++ b/public/docs/ts/latest/guide/forms.jade
@@ -1,205 +1,205 @@
include ../../../../_includes/_util-fns
-:markdown
+:marked
We’ve all used a form to login, submit a help request, place an order, book a flight,
- schedule a meeting and perform countless other data entry tasks.
+ schedule a meeting and perform countless other data entry tasks.
Forms are the mainstay of business applications.
-
+
Any seasoned web developer can slap together an HTML form with all the right tags.
It's more challenging to create a cohesive data entry experience that guides the
user efficiently and effectively through the workflow behind the form.
-
+
*That* takes design skills that are, to be frank, well out of scope for this chapter.
-
- It also takes framework support for
+
+ It also takes framework support for
**two-way data binding, change tracking, validation, and error handling**
... which we shall cover in this chapter on Angular forms.
-
+
We will build a simple form from scratch, one step at a time. Along the way we'll learn
-
+
- how to build an Angular form with a component and template
-
+
- the `ng-model` two-way data binding syntax for reading and writing values to input controls
-
+
- the `ng-control` directive to track the change state and validity of form controls
-
+
- the special CSS classes that `ng-control` adds to form controls and how we can use them to provide strong visual feedback
-
+
- how to display validation errors to users and enable/disable form controls
-
- - how to share information across controls with template local variables
+
+ - how to share information across controls with template local variables
.l-main-section
-:markdown
+:marked
## Template-Driven Forms
-
- Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with
+
+ Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with
the form-specific Directives and techniques described in this chapter.
.l-sub-section
- :markdown
+ :marked
That's not the only way to create a form but it's the way we'll cover in this chapter.
-:markdown
- We can build almost any form we need with an Angular template ... login forms, contact forms ... pretty much any business forms.
- We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors,
+:marked
+ We can build almost any form we need with an Angular template ... login forms, contact forms ... pretty much any business forms.
+ We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors,
conditionally enable or disable specific controls, trigger built-in visual feedback, and much more.
-
+
It will be pretty easy because Angular handles many of the repeative, boiler plate tasks we'd
otherwise wrestle with ourselves.
-
+
We'll discuss and learn to build the following template-driven form:
-
+
figure.image-display
img(src="/resources/images/devguide/forms/hf-1.png" alt="Clean Form")
-
-:markdown
+
+:marked
Here at the *Hero Employment Agency* we use this form to maintain personal information about the
heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis!
Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot.
-
+
If we delete the hero name, the form displays a validation error in an attention grabbing style:
figure.image-display
img(src="/resources/images/devguide/forms/hf-2.png" alt="Invalid, Name Required")
-:markdown
+:marked
Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red.
-
-.l-sub-section
- p We'll' customize the colors and location of the "required" bar with standard CSS.
-:markdown
+.l-sub-section
+ p We'll' customize the colors and location of the "required" bar with standard CSS.
+
+:marked
We will build this form in the following sequence of small steps
1. Create the `Hero` model class
1. Create the component that controls the form
1. Create a template with the initial form layout
- 1. Add the **ng-model** directive to each form input control
+ 1. Add the **ng-model** directive to each form input control
1. Add the **ng-control** directive to each form input control
1. Add custom CSS to provide visual feedback
1. Show and hide validation error messages
- 1. Handle form submission with **ng-submit**
- 1. Disable the form’s submit button until the form is valid
+ 1. Handle form submission with **ng-submit**
+ 1. Disable the form’s submit button until the form is valid
-:markdown
+:marked
## Setup
Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html).
- ## Create the Hero Model Class
-
- As users enter form data, we capture their changes and update an instance of a model.
+ ## Create the Hero Model Class
+
+ As users enter form data, we capture their changes and update an instance of a model.
We can't layout the form until we know what the model looks like.
-
+
A model can be as simple as a "property bag" that holds facts about a thing of application importance.
That describes well our `Hero` class with its three required fields (`id`, `name`, `power`)
and one optional field (`alterEgo`).
-
- Create a new file called `hero.ts` and give it the following class definition:
+
+ Create a new file called `hero.ts` and give it the following class definition:
+makeExample('forms/ts/src/app/hero.ts')
-:markdown
+:marked
It's an anemic model with few requirements and no behavior. Perfect for our demo.
-
- The TypeScript compiler generates a public field for each `public` constructor parameter and
+
+ The TypeScript compiler generates a public field for each `public` constructor parameter and
assigns the parameter’s value to that field automatically when we create new heroes like this:
```
let myHero = new Hero(42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover');
console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog"
- ```
- The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
+ ```
+ The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
.l-main-section
-:markdown
+:marked
## Create a Form component
-
- An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions.
-
- We begin with the Component because it states, in brief, what the Hero editor can do.
-
+
+ An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions.
+
+ We begin with the Component because it states, in brief, what the Hero editor can do.
+
Create a new file called `hero-form.component.ts` and give it the following definition:
+makeExample('forms/ts/src/app/hero-form.component.ts', 'first')
-:markdown
- There’s nothing special about this component, nothing to distinguish it from any component we've written before,
+:marked
+ There’s nothing special about this component, nothing to distinguish it from any component we've written before,
nothing form-specific about it ... except, perhaps, the tell-tale `FORM_DIRECTIVES` import.
-
+
Understanding this component requires only the Angular 2 concepts we’ve learned in previous chapters
-
- 1. We import a standard set of symbols from the Angular library.
+
+ 1. We import a standard set of symbols from the Angular library.
We don't have a template yet but we usually import `CORE_DIRECTIVES` and it doesn't surprise us to
import something called `FORM_DIRECTIVES`, given that we'll be writing a form
-
+
1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `` tag.
-
+
1. The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`.
-
- 1. We defined dummy data for `model` and `powers` as befits a demo.
+
+ 1. We defined dummy data for `model` and `powers` as befits a demo.
Down the road, we can inject a data service to get and save real data
- or perhaps expose these properties as [inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a
+ or perhaps expose these properties as [inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a
parent component. None of this concerns us now and these future changes won't affect our form.
-
+
1. We threw in a `diagnostic` property at the end to return a JSON representation of our model.
- It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later.
+ It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later.
We may wonder why we aren't writing the template inline in the component file as we have often done
elsewhere in the Developer Guide.
- There is no “right” answer for all occasions. We kind of like inline templates when they are short.
+ There is no “right” answer for all occasions. We kind of like inline templates when they are short.
Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to
write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code.
We also like short files with a clear and obvious purpose like this one.
-
+
We made a good choice to put the HTML template elsewhere. Let's write it.
.l-main-section
-:markdown
+:marked
## Revise the *app.ts*
-
+
`app.ts` is the application's root component. It will host our new `HeroFormComponent`.
-
+
Replace the contents of the "QuickStart" version with the following:
+makeExample('forms/ts/src/app/app.ts')
-:markdown
+:marked
.l-sub-section
- :markdown
+ :marked
There are only three changes:
-
+
1. We import the new `HeroFormComponent`.
-
+
1. The `template` is simply the new element tag identified by the component's `select` property.
-
+
1. The `directives` array tells Angular that our templated depends upon the `HeroFormComponent`
which is itself a Directive (as are all Components).
.l-main-section
-:markdown
+:marked
## Create an initial HTML Form Template
-
+
Create a new template file called `hero-form.component.html` and give it the following definition:
+makeExample('forms/ts/src/app/hero-form.component.html', 'start')
-:markdown
+:marked
That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and
opening them up for user input in input boxes.
-
+
The "Name" `` control has the HTML5 `required` attribute;
the "Alter Ego" `` control does not because `alterEgo` is optional.
-
+
We've got a "Submit" button at the bottom with some classes on it.
-
+
**We are not using Angular yet**. There are no bindings. No extra directives. Just layout.
-
- The `container`,`form-group`, `form-control`, and `btn` classes are CSS Bootstrap. Purely cosmetic.
+
+ The `container`,`form-group`, `form-control`, and `btn` classes are CSS Bootstrap. Purely cosmetic.
We're using Bootstrap to gussy up our form.
- Hey, what's a form without a little style!
+ Hey, what's a form without a little style!
.l-sub-section
- :markdown
+ :marked
Since we're using [CSS Boostrap](http://getbootstrap.com/css/).
now might be a good time to install it into our project.
We can do that with npm.
@@ -207,275 +207,275 @@ figure.image-display
Open a terminal window and enter the command:
code-example(language="html" escape="html").
npm install bootstrap
- :markdown
+ :marked
Open the `index.html` and add the following line wherever we like to put our CSS
+makeExample('forms/ts/src/index.html', 'bootstrap')(format=".")
-
+
.callout.is-important
header Angular Forms Does Not Require A Style Library
- :markdown
- Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or
+ :marked
+ Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or
the styles of any external library. We are welcome to use the CSS library we choose
... or none at all.
.l-main-section
-:markdown
+:marked
## Add Powers with ***ng-for**
Our hero may choose one super power from a fixed list of Agency-approved powers.
- We maintain that list internally (in `HeroFormComponent`).
-
+ We maintain that list internally (in `HeroFormComponent`).
+
We'll add a `select` to our
form and bind the options to the `powers` list using `NgFor`,
a technique we might have seen before in the ["Displaying Data"](./displaying-data.html) chapter.
-
+
Add the following HTML *immediately below* the "Alter Ego" group.
+makeExample('forms/ts/src/app/hero-form.component.html', 'powers')
-:markdown
+:marked
We are repeating the `` tag for each power in the list of Powers.
The `#p` local template variable is a different power in each iteration;
we display its name using the interpolation syntax with the double-curly-braces.
.l-main-section
-:markdown
+:marked
## Two-way data binding with ***ng-model**
We might be disappointed if we ran the app right now.
figure.image-display
img(src="/resources/images/devguide/forms/hf-3.png" alt="Early form with no binding")
-:markdown
- We quickly realize that we are not binding to the `Hero` yet.
- We know how to do that from earlier chapters.
+:marked
+ We quickly realize that we are not binding to the `Hero` yet.
+ We know how to do that from earlier chapters.
We learned show data on screen with a Property Binding in "[Displaying Data](./displaying-data.html)".
We learned to listen for DOM events with an
Event Binding and how to extract values from the screen
in "[User Input](./user-input.html)".
-
- Now we need to display, listen, and extract at the same time.
-
- We could use those techniques again in our form.
- Instead we'll introduce something new, the `NgModel` directive, that
+
+ Now we need to display, listen, and extract at the same time.
+
+ We could use those techniques again in our form.
+ Instead we'll introduce something new, the `NgModel` directive, that
makes binding our form to the model super-easy.
-
+
Find the `` tag for the "Name" and update it like this
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-1')
.l-sub-section
- :markdown
+ :marked
We appended a diagnostic interpolation after the input tag
- so we can see what we're doing.
+ so we can see what we're doing.
We left ourselves a note to throw it way when we're done.
-:markdown
- Focus on the binding syntax: `[(ng-model)]="..."`.
+:marked
+ Focus on the binding syntax: `[(ng-model)]="..."`.
If we ran the app right now and started typing in the "Name" input box,
- adding and deleting characters, we'd see them appearing and disappearing
+ adding and deleting characters, we'd see them appearing and disappearing
from the interpolated text.
At some point it might look like this.
figure.image-display
img(src="/resources/images/devguide/forms/ng-model-in-action.png" alt="ng-model in action")
-:markdown
+:marked
The diagnostic is evidence that we really are flowing values from the input box to the model and
back again. **That's two-way data binding!**
- Let's add similar `[(ng-model)]` bindings to "Alter Ego" and "Hero Power".
+ Let's add similar `[(ng-model)]` bindings to "Alter Ego" and "Hero Power".
We'll ditch the input box binding message
and add a new binding at the top to the component's `diagnostic` property.
Then we can confirm that we are in fact two-way data binding *to the entire Hero model*.
-
- After revision the core of our form should have three `[(ng-model)]` bindings that
+
+ After revision the core of our form should have three `[(ng-model)]` bindings that
look much like this:
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-2')
-:markdown
+:marked
If we ran the app right now and made a bunch of changes at some point it might look like this.
figure.image-display
img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" alt="ng-model in super action")
-:markdown
+:marked
We've changed every Hero model property and the diagnostic near the top of the form
confirms that our changes are reflected in the model.
-
+
** We're done with the diagnostic binding. Delete it now.**
.alert.is-helpful
- :markdown
+ :marked
Although `NgModel` is officially a "Forms" directive we can use `[(ng-model)]` and two-way binding outside of forms too.
-:markdown
+:marked
## Inside [(ng-model)]
Do we *really want* to know? If we're just happy that it works, move on to the next topic in this chapter.
-
+
Otherwise, stick around for this note.
.l-sub-section
- :markdown
+ :marked
The punctuation in the binding syntax, [()], is a good clue to what's going on.
-
+
We write a Property Binding to flow data from the model to a target property on screen.
We identify that target property by surrounding its name in brackets, [].
This is a one-way data binding **from the model to the view**.
-
+
We write an Event Binding to flow data from the target property on screen to the model.
We identify that target property by surrounding its name in parentheses, ().
This is a one-way data binding in the opposite direction **from the view to the model**.
-
- No wonder Angular chose to combine the punctuation as [()]
+
+ No wonder Angular chose to combine the punctuation as [()]
to signify a two-way data binding and a **flow of data in both directions**.
-
- In fact, we can break the `NgModel` binding into its two separate modes
+
+ In fact, we can break the `NgModel` binding into its two separate modes
as we do in this re-write of the "Name" `` binding:
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-3')
- :markdown
+ :marked
The Property Binding should feel familiar. The Event Binding might seem strange.
-
- The name `ng-model-change` is not an event we recognize.
- It is a real event property ... of the `NgModel` directive.
- When Angular sees a binding target in the form [(abc)],
+
+ The name `ng-model-change` is not an event we recognize.
+ It is a real event property ... of the `NgModel` directive.
+ When Angular sees a binding target in the form [(abc)],
it expects the `abc` directive to have an `abc` input property and an `abc-change` output property.
-
+
The other oddity is the template expression, `model.name = $event`.
- We're used to seeing an `$event` object coming from a DOM event.
- The `ng-model-change` property doesn't produce a DOM event; it's an Angular `EventEmitter`
+ We're used to seeing an `$event` object coming from a DOM event.
+ The `ng-model-change` property doesn't produce a DOM event; it's an Angular `EventEmitter`
property that returns the input box value when it fires ... which is precisely what
we should assign to the model's `name' property.
-
+
Nice to know but is it practical? We'd always prefer the `[(ng-model)]`.
We might split the binding if we had to do something special in
the event handling such as debounce or throttle the key strokes.
-
- Learn more about `NgModel` and other template syntax in the
+
+ Learn more about `NgModel` and other template syntax in the
[Template Syntax](./template-syntax.html) chapter.
-
+
.l-main-section
-:markdown
+:marked
## Track change-state and validity with **ng-control**
-
+
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
The `NgControl` directive keeps track of control state for us.
.callout.is-helpful
header NgControl requires Form
- :markdown
+ :marked
The `NgControl` is one of a family of `NgForm` directives that can only be applied to
a control within a `