chore(jade): upgrade to use `marked` filter
The `Transformers.markdown` (`:markdown`) filter is deprecated. This commit updates the entire docs project to use the `jstransformer-marked` (`:marked') filter.
This commit is contained in:
parent
0f61ea288f
commit
e86fde8dc9
|
@ -60,5 +60,8 @@
|
|||
"q": "^1.4.1",
|
||||
"typescript": "~1.5.3",
|
||||
"yargs": "^3.23.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"jstransformer-marked": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|||
<script src="app.js"></script>
|
||||
...
|
||||
|
||||
: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=.*&quot;)/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=.*&quot;)/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
|
||||
|
|
|
@ -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 `<my-app>` tag in the `<body>` is
|
||||
the custom HTML element defined in the Dart file.
|
||||
|
||||
|
@ -149,7 +149,7 @@ p.
|
|||
Once the app is running,
|
||||
you should see <b>My First Angular 2 App</b> 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.
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
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
|
||||
|
@ -19,7 +19,7 @@ include ../../../_includes/_util-fns
|
|||
1. Run it
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Create a project folder
|
||||
|
||||
**Create a new folder** to hold our application project, perhaps like this:
|
||||
|
@ -28,7 +28,7 @@ include ../../../_includes/_util-fns
|
|||
cd angular2-quickstart
|
||||
```
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Install essential libraries
|
||||
|
||||
We'll use the **npm package manager** to install packages for
|
||||
|
@ -44,11 +44,11 @@ include ../../../_includes/_util-fns
|
|||
easy once we have it installed.
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
: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,23 +61,23 @@ 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
|
||||
:marked
|
||||
We're creating a visual component named **`AppComponent`** by chaining the
|
||||
`Component` and `Class` methods that belong to the **global Angular namespace, `ng`**.
|
||||
|
||||
|
@ -107,14 +107,14 @@ include ../../../_includes/_util-fns
|
|||
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.
|
||||
|
||||
|
@ -134,14 +134,14 @@ include ../../../_includes/_util-fns
|
|||
+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 `<head>` element:
|
||||
|
||||
>***angular2.sfx.dev.js***, the Angular 2 development library that puts
|
||||
|
@ -154,7 +154,7 @@ include ../../../_includes/_util-fns
|
|||
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
|
||||
|
@ -170,10 +170,10 @@ 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.
|
||||
|
||||
|
@ -182,7 +182,7 @@ include ../../../_includes/_util-fns
|
|||
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.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
:markdown
|
||||
:marked
|
||||
Dependency Injection is an important application design pattern.
|
||||
Angular has its own Dependency Injection framework and
|
||||
we really can't build an Angular application without it.
|
||||
|
@ -7,7 +7,7 @@ include ../../../../_includes/_util-fns
|
|||
In this chapter we'll learn what Dependency Injection is, why we want it, and how to use it.
|
||||
<a name="why-di"></a>
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Why Dependency Injection?
|
||||
|
||||
Let's start with the following code.
|
||||
|
@ -95,7 +95,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
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:
|
||||
```
|
||||
|
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
|
|||
The critical point is this: `Car` itself did not have to change.
|
||||
We'll take care of the consumer's problem soon enough.
|
||||
|
||||
:markdown
|
||||
: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
|
||||
|
@ -163,7 +163,7 @@ include ../../../../_includes/_util-fns
|
|||
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
|
||||
|
@ -200,9 +200,9 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
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';
|
||||
|
@ -257,7 +257,7 @@ include ../../../../_includes/_util-fns
|
|||
```
|
||||
<a name="di-metadata"></a>
|
||||
.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`.
|
||||
|
@ -269,7 +269,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
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.
|
||||
|
@ -341,10 +341,10 @@ include ../../../../_includes/_util-fns
|
|||
**The `@Injectable()` decoration catches our eye!**
|
||||
|
||||
.alert.is-critical
|
||||
:markdown
|
||||
: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
|
||||
: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.
|
||||
|
||||
|
@ -357,7 +357,7 @@ include ../../../../_includes/_util-fns
|
|||
TypeScript generates metadata for *any* class with a decorator and *any* decorator will do.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a name="providers"></a>
|
||||
## Injector Providers
|
||||
|
||||
|
@ -468,13 +468,13 @@ include ../../../../_includes/_util-fns
|
|||
}
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
: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,
|
||||
a fact we can't know until runtime.
|
||||
:markdown
|
||||
: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:
|
||||
|
@ -485,12 +485,12 @@ include ../../../../_includes/_util-fns
|
|||
};
|
||||
```
|
||||
.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 `Logger` and `UserService` classes serve as tokens for their own class providers.
|
||||
:markdown
|
||||
:marked
|
||||
Finally, we create the provider and adjust the bootstrapping to include that provider
|
||||
among its provider registrations.
|
||||
```
|
||||
|
@ -552,7 +552,7 @@ include ../../../../_includes/_util-fns
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
# Next Steps
|
||||
We learned the basics of Angular Dependency Injection in this chapter.
|
||||
|
||||
|
@ -563,7 +563,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.l-main-section
|
||||
<a name="forward-ref"></a>
|
||||
: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.
|
||||
If we define every class in its own file, there is nothing in this note to worry about.
|
||||
|
@ -588,7 +588,7 @@ 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`
|
||||
|
@ -596,7 +596,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
The `alert` simulates the action of the Dependency Injector at runtime
|
||||
when it attempts to create a `HeroesComponent`.
|
||||
:markdown
|
||||
:marked
|
||||
Run it. The alert appears but displays nothing.
|
||||
This is the equivalent of the null reference error thrown at runtime.
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
<!-- http://plnkr.co/edit/x9JYbC -->
|
||||
|
||||
: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 `<my-app>` 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 `<my-app>`
|
||||
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
|
||||
inside the `<my-app>` 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 `<ul>` and `<li>` tags. Let's focus on the `<li>` tag.
|
||||
+makeExample('displaying-data/ts/src/app/app.2.ts', 'li-repeater')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We added a somewhat mysterious `*ng-for` to the `<li>` element.
|
||||
That's the Angular "repeater" directive.
|
||||
It's presence on the `<li>` tag marks that `<li>` 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.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
<!-- http://plnkr.co/edit/wg154K -->
|
||||
: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.
|
||||
Forms are the mainstay of business applications.
|
||||
|
@ -31,15 +31,15 @@ include ../../../../_includes/_util-fns
|
|||
- 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
|
||||
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
|
||||
: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.
|
||||
|
@ -52,7 +52,7 @@ include ../../../../_includes/_util-fns
|
|||
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!
|
||||
|
||||
|
@ -63,13 +63,13 @@ figure.image-display
|
|||
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
|
||||
:marked
|
||||
We will build this form in the following sequence of small steps
|
||||
|
||||
1. Create the `Hero` model class
|
||||
|
@ -82,7 +82,7 @@ figure.image-display
|
|||
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).
|
||||
|
||||
|
@ -99,7 +99,7 @@ figure.image-display
|
|||
|
||||
+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
|
||||
|
@ -111,7 +111,7 @@ figure.image-display
|
|||
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.
|
||||
|
@ -122,7 +122,7 @@ figure.image-display
|
|||
|
||||
+makeExample('forms/ts/src/app/hero-form.component.ts', 'first')
|
||||
|
||||
:markdown
|
||||
: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.
|
||||
|
||||
|
@ -155,7 +155,7 @@ figure.image-display
|
|||
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`.
|
||||
|
@ -163,9 +163,9 @@ figure.image-display
|
|||
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`.
|
||||
|
@ -176,14 +176,14 @@ figure.image-display
|
|||
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.
|
||||
|
||||
|
@ -199,7 +199,7 @@ figure.image-display
|
|||
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,19 +207,19 @@ figure.image-display
|
|||
Open a terminal window and enter the command:
|
||||
code-example(language="html" escape="html").
|
||||
npm install bootstrap
|
||||
:markdown
|
||||
:marked
|
||||
<br>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
|
||||
: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`).
|
||||
|
@ -231,19 +231,19 @@ figure.image-display
|
|||
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 `<options>` 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
|
||||
: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)".
|
||||
|
@ -262,12 +262,12 @@ figure.image-display
|
|||
+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.
|
||||
We left ourselves a note to throw it way when we're done.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Focus on the binding syntax: `[(ng-model)]="..."`.
|
||||
|
||||
If we ran the app right now and started typing in the "Name" input box,
|
||||
|
@ -276,7 +276,7 @@ figure.image-display
|
|||
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!**
|
||||
|
||||
|
@ -290,27 +290,27 @@ figure.image-display
|
|||
|
||||
+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, <span style="font-family:courier"><b>[()]</b></span>, 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.
|
||||
|
@ -328,7 +328,7 @@ figure.image-display
|
|||
as we do in this re-write of the "Name" `<input>` binding:
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-3')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
<br>The Property Binding should feel familiar. The Event Binding might seem strange.
|
||||
|
||||
The name `ng-model-change` is not an event we recognize.
|
||||
|
@ -350,7 +350,7 @@ figure.image-display
|
|||
[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.
|
||||
|
@ -358,10 +358,10 @@ figure.image-display
|
|||
|
||||
.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 `<form`> tag.
|
||||
:markdown
|
||||
:marked
|
||||
Our application can ask an `NgControl` instance if
|
||||
* the user touched the control (`ng-touched` | `ng-untouched`)
|
||||
* the value changed (`ng-pristine` | `ng-dirty`)
|
||||
|
@ -376,18 +376,18 @@ figure.image-display
|
|||
we should **add `ng-control`to all three of our form controls**,
|
||||
starting with the "Name" input box
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-1')
|
||||
:markdown
|
||||
:marked
|
||||
Be sure to assign a unique name to each `ng-control` directive.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Angular registers controls under their `ng-control` names
|
||||
with the `NgForm`.
|
||||
We didn't add the `NgForm` directive explicitly but it's here
|
||||
and we'll talk it [later in this chapter](#ng-form).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Add Custom CSS for Visual Feedback
|
||||
|
||||
`NgControl` doesn't just track state. It updates the control with three classes, one
|
||||
|
@ -401,7 +401,7 @@ figure.image-display
|
|||
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-2')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
If we ran the app, focused our attention on the "Name" input box, and followed the next four steps *precisely*
|
||||
|
||||
1. Look but don't touched
|
||||
|
@ -413,7 +413,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src="/resources/images/devguide/forms/ng-control-class-changes.png" alt="Invalid Form")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a
|
||||
strong visual signal when the data are invalid and we want to mark required fields.
|
||||
|
||||
|
@ -422,17 +422,17 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src="/resources/images/devguide/forms/validity-required-indicator.png" alt="Invalid Form")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We achieve this effect by adding two styles to a new `styles.css` file
|
||||
that we add to our project as a sibling to `index.html`.
|
||||
|
||||
+makeExample('forms/ts/src/styles.css')
|
||||
:markdown
|
||||
:marked
|
||||
These styles select for the two Angular validity classes and the HTML 5 "required" attribute.
|
||||
|
||||
We update the `<head>` of the `index.html` to include this style sheet.
|
||||
+makeExample('forms/ts/src/index.html', 'styles')(format=".")
|
||||
:markdown
|
||||
:marked
|
||||
## Show and Hide Validation Error messages
|
||||
|
||||
We can do better.
|
||||
|
@ -445,14 +445,14 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src="/resources/images/devguide/forms/name-required-error.png" alt="Name required")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
To achieve this effect we extend the `<input>` tag with
|
||||
1. a [local template variable](./template-syntax.html#local-vars)
|
||||
1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid.
|
||||
|
||||
Here's how we do it for the "name" input box:
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'name-with-error-msg')
|
||||
:markdown
|
||||
:marked
|
||||
We initialized the template local variable with the word "form" (`#name="form"`)
|
||||
|
||||
Angular recognizes that syntax and sets the `name` varable
|
||||
|
@ -464,7 +464,7 @@ figure.image-display
|
|||
if it becomes invalid, the message is revealed.
|
||||
<a id="ng-form"></a>
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Recall from the previous section that `ng-control` registered this input box with the
|
||||
`NgForm` directive as "name".
|
||||
|
||||
|
@ -474,7 +474,7 @@ figure.image-display
|
|||
|
||||
+makeExample('forms/ts/src/app/hero-form.component.ts', 'directives')
|
||||
<br>
|
||||
:markdown
|
||||
:marked
|
||||
The `NgForm` directive supplements the the `form` element with additional features.
|
||||
It collects `Controls` (elements identified by an `ng-control` directive)
|
||||
and monitors their properties including their validity.
|
||||
|
@ -484,7 +484,7 @@ figure.image-display
|
|||
In this example, we are pulling the "name" control out of its `controls` collection
|
||||
and assigning it to the template local variable so that we can
|
||||
access the control's properties ... such as the control's own `valid` property.
|
||||
:markdown
|
||||
:marked
|
||||
The "AlterEgo" is optional so we can leave that be.
|
||||
|
||||
"Power" selection is required.
|
||||
|
@ -493,7 +493,7 @@ figure.image-display
|
|||
power to valid value.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Submit the form with **ng-submit**
|
||||
The user should be able to submit this form after filling it in.
|
||||
The "Submit" button at the bottom of the form
|
||||
|
@ -505,7 +505,7 @@ figure.image-display
|
|||
and bind it to our `HeroFormComponent.submit()` method with an EventBinding
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-submit')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We slipped in something extra there at the end! We defined a
|
||||
template local variable, **`#hf`**, and initialized it with the value, "form".
|
||||
|
||||
|
@ -517,7 +517,7 @@ figure.image-display
|
|||
the `hf` variable to the button's `disabled` property
|
||||
using an Event Binding. Here's the code:
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'submit-button')
|
||||
:markdown
|
||||
:marked
|
||||
If we run the application now, we find that the button is enabled.
|
||||
It doesn't do anything useful yet but it's alive.
|
||||
|
||||
|
@ -534,18 +534,18 @@ figure.image-display
|
|||
2. Reference that variable in a button some 50 lines away.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Toggle two form regions (Extra Credit)
|
||||
Submitting the form isn't terribly dramatic at the moment.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An unsurprising observation for a demo. To be honest,
|
||||
jazzing it up won't teach us anything new about forms.
|
||||
But this is an opportunity to exercise some of our newly won
|
||||
binding skills.
|
||||
If we're not interested, we can skip to the chapter's conclusion
|
||||
and not miss a thing.
|
||||
:markdown
|
||||
:marked
|
||||
Let's do something more strikingly visual.
|
||||
Let's hide the data entry area and display something else.
|
||||
|
||||
|
@ -554,14 +554,14 @@ figure.image-display
|
|||
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'edit-div')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The main form is visible from the start because the
|
||||
the `submitted` property is false until we submit the form
|
||||
... as this fragment from the `HeroFormComponent` reminds us:
|
||||
|
||||
+makeExample('forms/ts/src/app/hero-form.component.ts', 'submitted')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
When we click the "Submit" button, the `submitted` flag becomes true and the form disappears
|
||||
as planned.
|
||||
|
||||
|
@ -569,7 +569,7 @@ figure.image-display
|
|||
Add the following block of HTML below the `<div>` wrapper we just wrote:
|
||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'submitted')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
There's our hero again, displayed read-only with interpolation bindings.
|
||||
This slug of HTML only appears while the component is in the submitted state.
|
||||
|
||||
|
@ -581,7 +581,7 @@ figure.image-display
|
|||
That's as much drama as we can muster for now.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Conclusion
|
||||
|
||||
The Angular 2 form discussed in this chapter takes advantage of the following framework features to provide support for data modification, validation and more:
|
||||
|
@ -612,7 +612,7 @@ figure.image-display
|
|||
app.ts,
|
||||
index.html,
|
||||
styles.css`)
|
||||
:markdown
|
||||
:marked
|
||||
Our final project folder structure should look like this:
|
||||
```
|
||||
angular2-forms
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
:markdown
|
||||
:marked
|
||||
# Angular 2 Glossary
|
||||
#sg-tables.showcase.shadow-1
|
||||
header.showcase-header
|
||||
|
@ -7,7 +7,7 @@
|
|||
and the almost right word is the difference between
|
||||
lightning and a lightning bug.</i> - Mark Twain
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Angular 2 has a vocabulary of its own.
|
||||
Most Angular 2 terms are everyday English words
|
||||
with a specific meaning within the Angular system.
|
||||
|
@ -17,16 +17,16 @@
|
|||
unexpected definitions.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Annotation
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
In practice a synonym for [Decoration](#decoration).
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Attribute Directive
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A category of [Directive](#directive) that can listen to and modify the behavior of
|
||||
other HTML elements, attributes, properties, and components. They are usually represented
|
||||
as HTML attributes, hence the name.
|
||||
|
@ -35,10 +35,10 @@
|
|||
an Attribute Directive.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Binding
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Almost always refers to [Data Binding](#data-binding) and the act of
|
||||
binding an HTML object property to a data object property.
|
||||
|
||||
|
@ -46,10 +46,10 @@
|
|||
between a "token" or "key" and a dependency [provider](#provider).
|
||||
This more rare usage should be clear in context.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Bootstrap
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
We launch an Angular application by "bootstrapping" it with the `bootstrap` method.
|
||||
The `bootstrap` method identifies an application's top level "root" [Component](#component)
|
||||
and optionally registers service [providers](#provider) with the
|
||||
|
@ -59,10 +59,10 @@
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Component
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An Angular class responsible for exposing data
|
||||
to a [View](#view) and handling most of the view’s display
|
||||
and user-interaction logic.
|
||||
|
@ -79,10 +79,10 @@
|
|||
the Component in the role of "Controller" or "View Model".
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Data Binding
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Applications display data values to a user and respond to user
|
||||
actions (clicks, touches, keystrokes).
|
||||
|
||||
|
@ -110,11 +110,11 @@
|
|||
Learn more about data binding in the
|
||||
[Template Syntax](./template-syntax.html#data-binding) chapter.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
<a id="decorator"></a> <a id="decoration"></a>
|
||||
## Decorator | Decoration
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A Decorator is a **function** that adds metadata to a class, its members (properties, methods) and function arguments.
|
||||
|
||||
Decorators are a JavaScript language [feature](https://github.com/wycats/javascript-decorators), implemented in TypeScript and proposed for ES2016 (AKA ES7).
|
||||
|
@ -140,14 +140,14 @@
|
|||
classes appearing below it in the file.
|
||||
|
||||
.alert.is-important
|
||||
:markdown
|
||||
:marked
|
||||
Always include the parentheses `()` when applying a decorator.
|
||||
A decorator is a **function** that must be called when applied.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Dependency Injection
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Dependency Injection is both a design pattern and a mechanism
|
||||
for creating and delivering parts of an application to other
|
||||
parts of an application that request them.
|
||||
|
@ -198,10 +198,10 @@
|
|||
There are other opportunities to register as well.
|
||||
|
||||
Learn more in the [Dependency Injection](./dependency-injection.html) chapter.
|
||||
:markdown
|
||||
:marked
|
||||
## Directive
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An Angular class responsible for creating, re-shaping, and interacting with HTML elements
|
||||
in the browser DOM. Directives are Angular's most fundamental feature.
|
||||
|
||||
|
@ -232,10 +232,10 @@
|
|||
elements and their children.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## ECMAScript
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript).
|
||||
|
||||
The latest approved version of JavaScript is
|
||||
|
@ -249,43 +249,43 @@
|
|||
to ES5 JavaScript.
|
||||
|
||||
Angular 2 developers may choose to write in ES5 directly.
|
||||
:markdown
|
||||
:marked
|
||||
## ECMAScript 2015
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The lastest released version of JavaScript,
|
||||
[ECMAScript 2015](http://www.ecma-international.org/ecma-262/6.0/)
|
||||
(AKA "ES2015" or "ES6")
|
||||
:markdown
|
||||
:marked
|
||||
## ES2015
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Short hand for "[ECMAScript 2015](#ecmascript=2015)".
|
||||
:markdown
|
||||
:marked
|
||||
## ES6
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Short hand for "[ECMAScript 2015](#ecmascript=2015)".
|
||||
:markdown
|
||||
:marked
|
||||
## ES5
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Short hand for "ECMAScript 5", the version of JavaScript run by most modern browsers.
|
||||
See [ECMAScript](#ecmascript).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Injector
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An object in the Angular [dependency injection system](#dependency-injection)
|
||||
that can find a named "dependency" in its cache or create such a thing
|
||||
with a registered [provider](#provider).
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Input
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A directive property that can be the ***target*** of a
|
||||
[Property Binding](./template-syntax.html#property-binding).
|
||||
Data values flow *into* this property from the data source identified
|
||||
|
@ -293,10 +293,10 @@
|
|||
|
||||
See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Interpolation
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A form of [Property Data Binding](#data-binding) in which a
|
||||
[template expression](#template-expression) between double-curly braces
|
||||
renders as text. That text may be concatenated with neighboring text
|
||||
|
@ -306,15 +306,15 @@
|
|||
code-example(language="html" escape="html").
|
||||
<label>My current hero is {{hero.name}}</label>
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about interpolation in the
|
||||
[Template Syntax](./template-syntax.html#interpolation) chapter.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Output
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A directive property that can be the ***target*** of an
|
||||
[Event Binding](./template-syntax.html#property-binding).
|
||||
Events stream *out* of this property to the receiver identified
|
||||
|
@ -323,10 +323,10 @@
|
|||
See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Pipe
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An Angular pipe is a function that transforms input values to output values for
|
||||
display in a [view](#view). We use the `@Pipe` [decorator](decorator)
|
||||
to associate the pipe function with a name. We then can use that
|
||||
|
@ -337,13 +337,13 @@
|
|||
|
||||
code-example(language="html" escape="html").
|
||||
<label>Price: </label>{{product.price | currency}}
|
||||
:markdown
|
||||
:marked
|
||||
Learn more in the chapter on [pipes](./pipes.html) .
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Provider
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A Provider creates a new instance of a dependency for the Dependency Injection system.
|
||||
It relates a lookup token to code - sometimes called a "recipe" - that can create a dependency value.
|
||||
|
||||
|
@ -354,10 +354,10 @@
|
|||
See [Dependency Injection](#dependency-injection) chapter to learn more.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Router
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Most applications consist of many screens or [views](#view).
|
||||
The user navigates among them by clicking links and buttons
|
||||
and taking other similar actions that cause the application to
|
||||
|
@ -368,10 +368,10 @@
|
|||
of views.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Structural Directive
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A category of [Directive](#directive) that can
|
||||
shape or re-shape HTML layout, typically by adding, removing, or manipulating
|
||||
elements and their children.
|
||||
|
@ -380,35 +380,35 @@
|
|||
good examples in this category.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Template
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A template is a chunk of HTML that Angular uses to render a [view](#view) with
|
||||
the support and continuing guidance of an Angular [Directive](#directive),
|
||||
most notably a [Component](#component).
|
||||
|
||||
We write templates in a special [Template Syntax](./template-syntax.html).
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Template Expression
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
An expression in a JavaScript-like syntax that Angular evaluates within
|
||||
a [data binding](#data-binding). Learn how to write template expressions
|
||||
in the [Template Syntax](./template-syntax.html#template-expressions) chapter.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Transpile
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The process of transforming code written in one form of JavaScript
|
||||
(e.g., TypeScript) into another form of JavaScript (e.g., [ES5](#es5)).
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## TypeScript
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A version of JavaScript that supports most [ECMAScript 2015](#ecmascript=2015)
|
||||
language features and many features that may arrive in future versions
|
||||
of JavaScript such as [Decorators](#decorator).
|
||||
|
@ -426,10 +426,10 @@
|
|||
Learn more about TypeScript on its [website](http://www.typescriptlang.org/).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## View
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
A view is a portion of the screen that displays information and responds
|
||||
to user actions such as clicks, mouse moves, and keystrokes.
|
||||
|
||||
|
@ -443,10 +443,10 @@
|
|||
under the control of a [router](#rounter).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Zone
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Zones are a mechanism for encapsulating and intercepting
|
||||
a JavaScript application's asynchronous activity.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
:markdown
|
||||
:marked
|
||||
We learned the basics of Angular Dependency injection in an
|
||||
[earlier chapter](./dependency-injection.html).
|
||||
|
||||
|
@ -11,7 +11,7 @@ include ../../../../_includes/_util-fns
|
|||
interesting and useful results.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## The Injector Tree
|
||||
|
||||
In an [earlier chapter](./dependency-injection.html)
|
||||
|
@ -25,12 +25,12 @@ include ../../../../_includes/_util-fns
|
|||
and each component instance in that tree has its own injector!
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
That isn't literally true. Angular is more efficient than that. What is true is that each component instance
|
||||
has an injector and that components at different levels in the tree have different injectors.
|
||||
|
||||
It is helpful for our purposes to pretend that every component has its own injector.
|
||||
:markdown
|
||||
:marked
|
||||
Consider a simple variation on the Tour of Heroes application consisting of three different components:
|
||||
`HeroesApp`, `HeroesListComponent` and `HeroesCardComponent`.
|
||||
The `HeroesApp` holds a single instance of `HeroesListComponent`.
|
||||
|
@ -42,7 +42,7 @@ include ../../../../_includes/_util-fns
|
|||
figure.image-display
|
||||
img(src="/resources/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.
|
||||
|
||||
When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.
|
||||
|
@ -52,18 +52,18 @@ figure.image-display
|
|||
If we run out of ancestors, Angular throws an error.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
There's a third possibililty. An intermediate component can declare that it is the "host" component.
|
||||
The hunt for providers will climb no higher than the injector for this host component.
|
||||
We'll reserve discussion of this option for another day.
|
||||
:markdown
|
||||
:marked
|
||||
Such a proliferation of injectors makes little sense until we consider the possiblity that injectors at different levels can be
|
||||
configured with different providers. We don't *have* to re-configure providers at every level. But we *can*.
|
||||
|
||||
If we don't re-configure, the tree of injectors appears to be flat. All requests bubble up to the root injector that we
|
||||
configured with the `bootstrap` method.
|
||||
|
||||
The ability to configure one or more providers at different levels opens up interesting and useful possibilities.
|
||||
The ability to configure one or more providers at different levels opens up interesting and useful possibilities.
|
||||
|
||||
Let’s return to our Car example.
|
||||
Suppose configured the root injector (marked as A) with providers for `Car`, `Engine` and `Tires`.
|
||||
|
@ -80,7 +80,7 @@ figure.image-display
|
|||
img(src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="injector tree")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Component Injectors
|
||||
|
||||
In the previous section, we talked about injectors and how they are organized like a tree. Lookups follow the injector tree upwards until they found the requested thing to inject. But when do we actually want to provide bindings on the root injector and when do we want to provide them on a child injector?
|
||||
|
@ -300,7 +300,7 @@ figure.image-display
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Dependency Visibility
|
||||
|
||||
[TODO] (bindings vs viewBindings) This has been postponed for now until come up with a decent use case
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
:markdown
|
||||
:marked
|
||||
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
||||
|
||||
Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket.
|
||||
|
@ -18,7 +18,7 @@ include ../../../../_includes/_util-fns
|
|||
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Using Pipes
|
||||
|
||||
A pipe takes in data as input and transforms it to a desired output.
|
||||
|
@ -33,29 +33,29 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
+makeExample('pipes/ts/src/app/app.ts', 'hero-birthday')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Focus on the component's template to see how we applied the built-in `DatePipe`
|
||||
while binding the `birthday` property.
|
||||
+makeExample('pipes/ts/src/app/app.html', 'hero-birthday-template')(format=".")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're
|
||||
using to flow the birthday value on the left through to the `Date` pipe function on the right.
|
||||
All pipes work this way.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Built-in pipes
|
||||
Angular comes with a stock set of pipes such as
|
||||
`DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`.
|
||||
They are all immediately available for use in any template.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about these and many other built-in pipes in the the [API Reference](../api/);
|
||||
filter for entries that include the word "pipe".
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Parameterizing a Pipe
|
||||
A pipe may accept any number of optional parameters to fine-tune its output.
|
||||
|
||||
|
@ -67,7 +67,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
+makeExample('pipes/ts/src/app/app.html', 'format-birthday')(format=".")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The parameter value can be any valid
|
||||
[template expression](./template-expression.html#template-expressions)
|
||||
such as a string literal or a component property.
|
||||
|
@ -76,7 +76,7 @@ include ../../../../_includes/_util-fns
|
|||
to the component's `format` property.
|
||||
+makeExample('pipes/ts/src/app/hero-birthday.2.ts', 'hero-birthday2')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We also added a button to the template and bound its click event to the component's `toggleFormat` method.
|
||||
That method toggles the component's `format` property between a short form
|
||||
('shortDate') and a longer form ('fullDate').
|
||||
|
@ -87,11 +87,11 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
|
||||
:markdown
|
||||
:marked
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html).
|
||||
:markdown
|
||||
:marked
|
||||
## Chaining pipes
|
||||
We can chain pipes together in potentially useful combinations.
|
||||
In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe`
|
||||
|
@ -100,7 +100,7 @@ figure.image-display
|
|||
|
||||
+makeExample('pipes/ts/src/app/app.html', 'chained-birthday')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
If we pass a parameter to a filter, we have to add parentheses
|
||||
to help the template compiler with the evaluation order.
|
||||
The following example displays
|
||||
|
@ -112,7 +112,7 @@ figure.image-display
|
|||
p Future improvements in the template compiler may eliminate the need for parentheses.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Custom Pipes
|
||||
|
||||
We can write our own custom pipes.
|
||||
|
@ -127,7 +127,7 @@ figure.image-display
|
|||
-->
|
||||
+makeExample('pipes/ts/src/app/exponential-strength-pipe.ts')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
This pipe definition reveals several few key points
|
||||
* We import the `Pipe` decorator from the Angular library (while getting the usual symbols)
|
||||
* A pipe is a class
|
||||
|
@ -146,7 +146,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Two things to note:
|
||||
1. We use the pipe in the template expression exactly as we described in the pipe's comments.
|
||||
We pass the value to transform from the left and give our pipe an exponent parameter of `10`.
|
||||
|
@ -155,12 +155,12 @@ figure.image-display
|
|||
|
||||
.callout.is-critical
|
||||
header Remember the pipes array!
|
||||
:markdown
|
||||
:marked
|
||||
Angular reports an error if we neglect to list our custom pipe.
|
||||
We didn't list the `DatePipe` in our previous example because all
|
||||
Angular built-in pipes are pre-registered.
|
||||
Custom pipes must be registered manually.
|
||||
:markdown
|
||||
:marked
|
||||
If we are inclined to try this in a live-coding tool (such a [plunker](http://plnkr.co/)),
|
||||
we can probe its behavior by changing the value and the optional exponent in the template.
|
||||
|
||||
|
@ -173,10 +173,10 @@ figure.image-display
|
|||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/pipes/power-boost-calculator.png' alt="Power Boost Calculator")
|
||||
:markdown
|
||||
:marked
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Stateful Pipes
|
||||
|
||||
There are two categories of pipes, stateless and stateful.
|
||||
|
@ -200,7 +200,7 @@ figure.image-display
|
|||
In the next example, we bind a simple promise to a view with the async pipe.
|
||||
+makeExample('pipes/ts/src/app/app.ts', 'async-message')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The Async pipe saves boilerplate in the component code.
|
||||
The component doesn't have to subscribe to the async data source,
|
||||
it doesn't extract the resolved values and expose them for binding,
|
||||
|
@ -218,11 +218,11 @@ figure.image-display
|
|||
Here's how we'll decorate our new stateful `FetchJsonPipe` that
|
||||
makes an HTTP `fetch` request and (eventually) displays the data in the server's response:
|
||||
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts', 'pipe-metadata')
|
||||
:markdown
|
||||
:marked
|
||||
Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file.
|
||||
The pipe makes a one-time async request to the server and eventually receives the JSON response.
|
||||
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts')
|
||||
:markdown
|
||||
:marked
|
||||
Next we use this pipe in two template bindings where we
|
||||
1. display hero names in an `ng-for` repeater
|
||||
1. chain the fetched results to the built-in `JsonPipe` that renders
|
||||
|
@ -234,7 +234,7 @@ figure.image-display
|
|||
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Next Steps
|
||||
|
||||
Pipes are a great way to encapsulate and share common display-value
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
# App Navigation with the Router
|
||||
It's coming soon!
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What's not to love?
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
# Template Syntax
|
||||
Our Angular application manages what the user sees and does through the interaction of a Component class instance and its user-facing template.
|
||||
|
||||
|
@ -37,13 +37,13 @@ include ../../../../_includes/_util-fns
|
|||
>[Template Expression Operators](#expression-ops)
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## HTML
|
||||
HTML is the language of the Angular template. Our “[QuickStart](./quickstart.html)” application had a template that was pure HTML
|
||||
|
||||
code-example(format="" language="html" escape="html").
|
||||
<h3>My First Angular Application</h3>
|
||||
:markdown
|
||||
:marked
|
||||
Almost all HTML syntax is valid template syntax. The `<script>` element is a notable exception; it is forbidden in order to eliminate any possibility of JavaScript injection attacks (in practice it is simply ignored).
|
||||
|
||||
Some legal HTML doesn’t make much sense in a template. The `<html>`, `<body>` and `<base>` elements have no useful role in our repertoire. Pretty much everything else is fair game.
|
||||
|
@ -53,13 +53,13 @@ code-example(format="" language="html" escape="html").
|
|||
Let’s turn to the first form of data binding - interpolation - to see how much richer Template HTML can be.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Interpolation
|
||||
We met the double-curly braces of interpolation, `{{` and `}}`, early in our Angular education.
|
||||
|
||||
code-example(format="" language="html" escape="html").
|
||||
<p>My current hero is {{currentHero.firstName}}</p>
|
||||
:markdown
|
||||
:marked
|
||||
We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
|
||||
|
||||
code-example(format="" language="html" escape="html").
|
||||
|
@ -67,7 +67,7 @@ code-example(format="" language="html" escape="html").
|
|||
{{title}}
|
||||
<img src="{{heroImageUrl}}" height=30>
|
||||
</h3>
|
||||
:markdown
|
||||
:marked
|
||||
The material between the braces is often the name of a component property. Angular replaces that name with the
|
||||
string value of the corresponding component property. In this example, Angular evaluates the `title` and `heroImageUrl` properties
|
||||
and "fills in the blanks", displaying first a bold application title and then a heroic image.
|
||||
|
@ -77,7 +77,7 @@ code-example(format="" language="html" escape="html").
|
|||
code-example(format="" language="html" escape="html").
|
||||
<!-- "The sum of 1 + 1 is 2" -->
|
||||
<h1>The sum of 1 + 1 is {{1 + 1}}</h1>
|
||||
:markdown
|
||||
:marked
|
||||
Angular evaluates all expressions in double curly braces, converts the expression results to strings, and concatenates them with neighboring literal strings. Finally,
|
||||
it assigns this composite interpolated result to an **element or directive property**.
|
||||
|
||||
|
@ -89,7 +89,7 @@ code-example(format="" language="html" escape="html").
|
|||
But before we explore that assertion, we’ll take a closer look at template expressions.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Template Expressions
|
||||
We saw a template expression within the interpolation braces.
|
||||
We’ll see template expressions again in [Property Bindings](#property-binding) (`[property]="expression"`) and
|
||||
|
@ -108,12 +108,12 @@ code-example(format="" language="html" escape="html").
|
|||
|
||||
The **expression context** is typically the **component instance** supporting a particular template instance.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
We speak of component and template ***instances***. Angular creates multiple concrete instances from a component class and its template.
|
||||
|
||||
For example, we may define a component and template to display a list item and tell Angular to create new instances of that component/template pair for each item in a list. There’s a separate, independent expression context for each item in that list as well.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
When we see `title` wrapped in double-curly braces,
|
||||
we know that it is a property of a parent component.
|
||||
When we see `[disabled]="isUnchanged"` or `(click)="onCancel()”`,
|
||||
|
@ -128,14 +128,14 @@ code-example(format="" language="html" escape="html").
|
|||
Another is the **`$event`** variable that contains information about an event raised on an element;
|
||||
we’ll talk about that when we consider [Event Bindings](#event-binding).
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Although we can write quite complex template expressions, we strongly discourage that practice. Most readers frown on JavaScript in the HTML. A property name or method call should be the norm. An occasional Boolean negation (`!`) is OK. Otherwise, confine application and business logic to the component itself where it will be easier to develop and test.
|
||||
:markdown
|
||||
:marked
|
||||
Now that we have a feel for template expressions, we’re ready to learn about the varieties of data binding syntax beyond Interpolation.
|
||||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="binding-syntax"></a>
|
||||
## Binding syntax overview
|
||||
Data binding is a mechanism for coordinating what users see with application data values. While we could push values to and pull values from HTML,
|
||||
|
@ -178,7 +178,7 @@ table
|
|||
[(target)] = "expression"
|
||||
bindon-target = "expression"
|
||||
td Two-way
|
||||
:markdown
|
||||
:marked
|
||||
**Template expressions must be surrounded in quotes**
|
||||
except for interpolation expressions which must not be quoted.
|
||||
|
||||
|
@ -226,7 +226,7 @@ table
|
|||
We are setting the *properties* of DOM elements, Components, and Directives.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### HTML Attribute vs. DOM Property
|
||||
|
||||
The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works.
|
||||
|
@ -268,18 +268,18 @@ table
|
|||
|
||||
**The HTML attribute and the DOM property are not the same thing even when they have the same name.**
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
This is so important, we’ll say it again.
|
||||
|
||||
**Template binding works with *properties* and *events*, not *attributes*.**
|
||||
|
||||
.callout.is-helpful
|
||||
header A world without attributes
|
||||
:markdown
|
||||
:marked
|
||||
In the world of Angular 2, the only role of attributes is to initialize element and directive state.
|
||||
When we data bind, we're dealing exclusively with element and directive properties and events.
|
||||
Attributes effectively disappear.
|
||||
:markdown
|
||||
:marked
|
||||
With this model firmly in mind, we are ready to discuss the variety of target properties to which we may bind.
|
||||
|
||||
### Binding Targets
|
||||
|
@ -348,7 +348,7 @@ table
|
|||
code-example(format="", language="html").
|
||||
<button [style.color] = "isSpecial ?'red' : 'green'">
|
||||
</div>
|
||||
:markdown
|
||||
:marked
|
||||
### Spelling target names
|
||||
The target name – whether between punctuation or after a prefix -
|
||||
should be spelled with **lowercase**. Although we can spell it in mixed-case,
|
||||
|
@ -369,7 +369,7 @@ table
|
|||
code-example(format="", language="html").
|
||||
Template parse errors:
|
||||
Can't bind to 'textcontent' since it isn't a known native property in ...
|
||||
:markdown
|
||||
:marked
|
||||
Notice that it forced mixed-case ""text**C**ontent" to lowercase "text**c**ontent".
|
||||
|
||||
The solution is to write the target property name in “**lower snake case**”,
|
||||
|
@ -380,14 +380,14 @@ code-example(format="", language="html").
|
|||
<hero-detail [is-active] = "isActive">
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
According to this rule, we should write `[inner-h-t-m-l]` to access the element’s `innerHTML` property.
|
||||
Fortunately, the Angular template parser recognizes `inner-html` as an acceptable alias for `innerHTML`.
|
||||
:markdown
|
||||
:marked
|
||||
Let’s descend from the architectural clouds and look at each of these binding types in concrete detail.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Property Binding
|
||||
We write a template **Property Binding** when we want to set a property of a view element to the value of a template expression.
|
||||
|
||||
|
@ -429,11 +429,11 @@ code-example(format="", language="html").
|
|||
<div [ng-class]="special">NgClass is special</div>
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
|
||||
one of the property names listed in the directive’s `inputs` array or a property decorated with `@Input()`.
|
||||
Such inputs map to the directive’s own properties.
|
||||
:markdown
|
||||
:marked
|
||||
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
|
||||
|
||||
### Property Binding template expressions
|
||||
|
@ -470,7 +470,7 @@ code-example(language="html").
|
|||
|
||||
<h3>The title is {{title}}</h3>
|
||||
<h3>[text-content]="'The title is '+title"></h3>
|
||||
:markdown
|
||||
:marked
|
||||
Interpolation is actually a convenient alternative for Property Binding in many cases.
|
||||
In fact, Angular translates those Interpolations into the corresponding Property Bindings
|
||||
before rendering the view.
|
||||
|
@ -481,7 +481,7 @@ code-example(language="html").
|
|||
both conforms to the rules and feels most natural for the task at hand.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="other-bindings"></a>
|
||||
## Attribute, Class, and Style Bindings
|
||||
The template syntax provides specialized one-way bindings for scenarios less well suited to Property Binding.
|
||||
|
@ -489,10 +489,10 @@ code-example(language="html").
|
|||
### Attribute Binding
|
||||
We can set the value of an attribute directly with an **Attribute Binding**.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
This is the only exception to the rule that a binding sets a target property. This is the only binding that creates and sets an attribute.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We have stressed throughout this chapter that setting an element property with a Property Binding is always preferred to setting the attribute with a string. Why does Angular offer Attribute Binding?
|
||||
|
||||
**We must use Attribute Binding when there is no element property to bind.**
|
||||
|
@ -506,12 +506,12 @@ code-example(language="html").
|
|||
We become painfull aware of this fact when we try to write something like this:
|
||||
code-example(language="html").
|
||||
<tr><td colspan="{{1+1}}">Three-Four</td></tr>
|
||||
:markdown
|
||||
:marked
|
||||
… and get the error:
|
||||
code-example(format="", language="html").
|
||||
Template parse errors:
|
||||
Can't bind to 'colspan' since it isn't a known native property
|
||||
:markdown
|
||||
:marked
|
||||
As the message says, the `<td>` element does not have a `colspan` property.
|
||||
It has the `colspan` attribute but Interpolation and Property Binding set properties, not attributes.
|
||||
|
||||
|
@ -562,11 +562,11 @@ code-example(format="", language="html").
|
|||
<div class="special" [class.special]="!isSpecial">This one is not so special</div>
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
While this is a fine way to toggle a single class name,
|
||||
we generally prefer the [NgClass directive](#ng-class) for managing multiple class names at the same time.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
### Style Binding
|
||||
|
||||
We can set inline styles with a **Style Binding**.
|
||||
|
@ -583,12 +583,12 @@ code-example(format="", language="html").
|
|||
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
While this is a fine way to set a single style,
|
||||
we generally prefer the [NgStyle directive](#ng-style) for when setting several inline styles at the same time.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Event Binding
|
||||
The bindings we’ve met so far flow data in one direction *from the component to an element*.
|
||||
|
||||
|
@ -621,7 +621,7 @@ code-example(format="", language="html").
|
|||
<input (ng-model-change)="firstName = $event">
|
||||
```
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
`ng-model-change` translates to the `ngModelChange` property of the `NgModel` directive.
|
||||
|
||||
Technically, Angular is matching the target binding name to a directive [output](#inputs-outputs) property,
|
||||
|
@ -630,7 +630,7 @@ code-example(format="", language="html").
|
|||
`ngModelChange` maps to the directive's hidden `update` property.
|
||||
|
||||
These details are not something we generally need or want to know.
|
||||
:markdown
|
||||
:marked
|
||||
If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error.
|
||||
|
||||
### $event and event handling expressions
|
||||
|
@ -689,10 +689,10 @@ code-example(format="", language="html").
|
|||
Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
`EventEmitter` events don’t bubble.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The result of an Event Binding expression determines if
|
||||
[event propagation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation)
|
||||
continues or stops with the current element.
|
||||
|
@ -707,7 +707,7 @@ code-example(format="", language="html").
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a name="ng-model"></a>
|
||||
## Two-Way Binding with NgModel
|
||||
When developing data entry forms we often want to both display a data property and update that property when the user makes changes.
|
||||
|
@ -745,14 +745,14 @@ code-example(format="", language="html").
|
|||
```
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Internally, Angular maps the term, `ng-model`, to an `ng-model` input property and an
|
||||
`ng-model-change` output property.
|
||||
That’s a specific example of a more general pattern in which it matches `[(x)]` to an `x` input property
|
||||
for Property Binding and an `x-change` output property for Event Binding.
|
||||
|
||||
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
|
||||
:markdown
|
||||
:marked
|
||||
*Before* we can use `NgModel`, we must import it via the `FORM_DIRECTIVES` directives array
|
||||
```
|
||||
import {FORM_DIRECTIVES} from ‘angular2/angular2`
|
||||
|
@ -760,7 +760,7 @@ code-example(format="", language="html").
|
|||
and include that array among the list of directives used by the component’s template (`directives: [FORM_DIRECTIVES]`).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a name="directives"></a>
|
||||
## Built-in Directives
|
||||
|
||||
|
@ -856,10 +856,10 @@ code-example(format="", language="html").
|
|||
<hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail>
|
||||
```
|
||||
.alert.is-critical
|
||||
:markdown
|
||||
:marked
|
||||
The leading asterisk (`*`) in front of `ng-if` is a critical part of this syntax.
|
||||
See the section below on [* and <template>](#star-template).
|
||||
:markdown
|
||||
:marked
|
||||
#### Visibility and NgIf are not the same
|
||||
We can show and hide an element sub-tree (the element and its children) with a [Class](#class-binding) or a [Style](#style-binding) binding:
|
||||
```
|
||||
|
@ -918,9 +918,9 @@ code-example(format="", language="html").
|
|||
<div *ng-for="#hero of heroes">{{hero.fullName}}</div>
|
||||
```
|
||||
.alert.is-critical
|
||||
:markdown
|
||||
:marked
|
||||
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax. See the section below on [* and <template>](#star-template).
|
||||
:markdown
|
||||
:marked
|
||||
The `ng-for` directive iterates over the `heroes` array returned by the parent component’s `heroes` property and stamps out instances of the `<div>` template.
|
||||
|
||||
The quoted text assigned to `ng-for` means “*take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the template instance*”. Angular creates one fresh instance of the `<div>` template for each hero in the array.
|
||||
|
@ -933,13 +933,13 @@ code-example(format="", language="html").
|
|||
|
||||
code-example(format="" language="html").
|
||||
<div *ng-for="#hero of heroes", #i=index">{{i+1}} - {{hero.fullName}}</div>
|
||||
:markdown
|
||||
:marked
|
||||
We can apply an `ng-for` repeater to Components as well,
|
||||
as we do in this following example with the `LittleHeroComponent`:
|
||||
|
||||
code-example(format="" language="html").
|
||||
<little-hero *ng-for="#hero of heroes" [hero]="hero"></little-hero>
|
||||
:markdown
|
||||
:marked
|
||||
The template in this case is defined by `LittleHeroComponent` itself. Angular creates a new instance of this component for each hero in the array and assigns the `hero` local *variable* to the `hero`* [input property](#inputs-outputs)* of each instance.
|
||||
|
||||
#### Micro-syntax
|
||||
|
@ -948,7 +948,7 @@ code-example(format="" language="html").
|
|||
We’ll talk about this in the next section about templates.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a name="star-template"></a>
|
||||
<a name="structural-directive"></a>
|
||||
## * and <template>
|
||||
|
@ -1002,14 +1002,14 @@ code-example(format="" language="html").
|
|||
|
||||
.callout.is-critical
|
||||
header Remember the brackets!
|
||||
:markdown
|
||||
:marked
|
||||
Don’t make the mistake of writing `ng-if="isActive"`!
|
||||
That syntax assigns the "isActive" string to the `ng-if` directive.
|
||||
In JavaScript a non-empty string is a truthy value so `ng-if` is always
|
||||
set `true` and always displays `hero-detail`
|
||||
… even when the parent component’s `isActive` property returns `false`!
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
#### Expanding `*ng-for`
|
||||
This same transformation applies to `*ng-for`. We can "de-sugar" the syntax ourselves and go from ...
|
||||
```
|
||||
|
@ -1036,7 +1036,7 @@ code-example(format="" language="html").
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="local-vars"></a>
|
||||
## Local template variables
|
||||
|
||||
|
@ -1060,9 +1060,9 @@ code-example(format="" language="html").
|
|||
combination, creates the variable, and assigns its value.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
`var-` is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`.
|
||||
:markdown
|
||||
:marked
|
||||
We can **reference a local template variable on the same element, on a sibling element, or on
|
||||
any of its children**.
|
||||
|
||||
|
@ -1111,13 +1111,13 @@ code-example(format="" language="html").
|
|||
endows it with additional form super powers.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
We know it's the Angular built-in `form` directive
|
||||
because we imported the `FORM_DIRECTIVES` collection
|
||||
and added it to the parent component's `directives` array.
|
||||
|
||||
Learn more about forms in the [Forms](./forms.html) chapter.
|
||||
:markdown
|
||||
:marked
|
||||
We assign the form object to the `hf` ("hero form") local template variable
|
||||
and use it twice.
|
||||
1. We pass it to the `onSubmit` method of the parent component process form values.
|
||||
|
@ -1125,7 +1125,7 @@ code-example(format="" language="html").
|
|||
detect by evaluating `hf.form.valid`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="inputs-outputs"></a>
|
||||
## Input and Output Properties
|
||||
When Directives are the **targets of data binding**, they must expose **input** and **output** properties.
|
||||
|
@ -1190,7 +1190,7 @@ code-example(format="" language="html").
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="expression-ops"></a>
|
||||
## Template Expression Operators
|
||||
The template expression language employs a subset of JavaScript syntax supplemented with some special operators
|
||||
|
@ -1206,37 +1206,37 @@ code-example(format="" language="html").
|
|||
code-example(format="" language="html").
|
||||
<!-- Force title to uppercase -->
|
||||
<div>{{ title | uppercase }}</div>
|
||||
:markdown
|
||||
:marked
|
||||
The pipe operator passes the result of an expression on the left to a pipe function on the right.
|
||||
|
||||
We can also chain expressions through multiple pipes
|
||||
code-example(format="" language="html").
|
||||
<!-- Pipe chaining: force title to uppercase, then to lowercase -->
|
||||
<div>{{ title | uppercase | lowercase }}</div>
|
||||
:markdown
|
||||
:marked
|
||||
<a id="elvis"></a>
|
||||
### The Elvis Operator ( ?. ) and null property paths
|
||||
|
||||
The Angular **“Elvis” operator ( ?. )** is a fluent and convenient way to guard against null and undefined values in property paths as we see it here, protecting against a view render failure if the `currentHero` is null.
|
||||
code-example(format="" language="html").
|
||||
<div>The current hero’s name is {{currentHero?.firstName}}</div>
|
||||
:markdown
|
||||
:marked
|
||||
Let’s elaborate on the problem and this particular solution.
|
||||
|
||||
What happens when the following data bound `title` property is null?
|
||||
code-example(format="" language="html").
|
||||
<div>The title is {{ title }}</div>
|
||||
:markdown
|
||||
:marked
|
||||
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
|
||||
|
||||
Suppose the template expression involves a property path as in this next example where we’re displaying the `firstName` of a null hero.
|
||||
code-example(format="" language="html").
|
||||
<div>The null hero's name is {{nullHero.firstName}}</div>
|
||||
:markdown
|
||||
:marked
|
||||
JavaScript throws a null reference error and so does Angular:
|
||||
code-example(format="" language="html").
|
||||
TypeError: Cannot read property 'firstName' of null in [null]
|
||||
:markdown
|
||||
:marked
|
||||
Surprisingly, the entire view just disappears.
|
||||
|
||||
We could claim that this is reasonable behavior if we believe that the `hero` property must never be null.
|
||||
|
@ -1254,7 +1254,7 @@ code-example(format="" language="html").
|
|||
code-example(format="" language="html").
|
||||
<!-- No hero, div not displayed, no error -->
|
||||
<div *ng-if="nullHero">The null hero's name is {{nullHero?.firstName}}</div>
|
||||
:markdown
|
||||
:marked
|
||||
This approach has merit but it’s cumbersome, especially if the property path is long.
|
||||
Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
|
||||
|
||||
|
@ -1262,13 +1262,13 @@ code-example(format="" language="html").
|
|||
code-example(format="" language="html").
|
||||
<!-- No hero, no problem! -->
|
||||
<div>The null hero's name is {{nullHero?.firstName}}</div>
|
||||
:markdown
|
||||
:marked
|
||||
It’s great with long property paths too:
|
||||
```
|
||||
a?.b?.c?.d
|
||||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What Next?
|
||||
We’ve completed our survey of Template Syntax. Time to put that knowledge to work as we write our own Components and Directives.
|
|
@ -1,11 +1,11 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
When the user clicks a link, pushes a button, or types on the keyboard
|
||||
we want to know about it. These user actions all raise DOM events.
|
||||
In this chapter we learn to bind to those events using the Angular Event Binding syntax.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Binding to User Input Events
|
||||
|
||||
We can listen to [any DOM event](https://developer.mozilla.org/en-US/docs/Web/Events)
|
||||
|
@ -15,7 +15,7 @@ include ../../../../_includes/_util-fns
|
|||
A click Event Binding makes for a quick illustration.
|
||||
+makeExample('user-input/ts/src/app/app.html', 'click-me-button')(format=".")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The `(click)` to the left of the equal sign identifies the button's click event as the **target of the binding**.
|
||||
The text within quotes on the right is the "**template expression**" in which we
|
||||
respond to the click event by calling the component's `onClickMe` method. A [template expression](./template-syntax.html#template-expressions) is a subset
|
||||
|
@ -29,19 +29,19 @@ include ../../../../_includes/_util-fns
|
|||
These sample can be found in http://plnkr.co/edit/mr63T5
|
||||
-->
|
||||
+makeExample('user-input/ts/src/app/app.ts', 'click-me-component')
|
||||
:markdown
|
||||
:marked
|
||||
The `onClickMe` in the template refers to the `onClickMe` method of the component.
|
||||
When the user clicks the button, Angular calls the component's `onClickMe` method.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Get user input from the $event object
|
||||
We can bind to all kinds of events. Let's bind to the "keyup" event of an input box and replay
|
||||
what the user types back onto the screen.
|
||||
|
||||
This time we'll both listen to an event and grab the user's input.
|
||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up-component')
|
||||
:markdown
|
||||
:marked
|
||||
Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere.
|
||||
|
||||
The shape of the `$event` object is determined by whatever raises the event.
|
||||
|
@ -60,10 +60,10 @@ code-example().
|
|||
a | ab | abc | ab | a | |
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1")
|
||||
:markdown
|
||||
:marked
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Get user input from a local template variable
|
||||
There's another way to get the user data without the `$event` variable.
|
||||
|
||||
|
@ -74,7 +74,7 @@ figure.image-display
|
|||
Let's demonstrate with a clever keystroke loopback in a single line of template HTML.
|
||||
We don't actually need a dedicated component to do this but we'll make one anyway.
|
||||
+makeExample('user-input/ts/src/app/app.ts', 'loop-back-component')
|
||||
:markdown
|
||||
:marked
|
||||
We've declared a template local variable named `box` on the `<input>` element.
|
||||
The `box` variable is a reference to the `<input>` element itself which means we can
|
||||
grab the input element's `value` and display it
|
||||
|
@ -93,14 +93,14 @@ figure.image-display
|
|||
variable than to go through the `$event` object. Maybe we can re-write our previous
|
||||
"key-up" example using the variable to acquire the user's' input. Let's give it a try.
|
||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up2-component')
|
||||
:markdown
|
||||
:marked
|
||||
That sure seems easier.
|
||||
An especially nice aspect of this approach is that our component code gets clean data values from the view.
|
||||
It no longer requires knowledge of the `$event` and its structure.
|
||||
|
||||
<a id="key-event"></a>
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Key event filtering (with `key.enter`)
|
||||
Perhaps we don't care about every keystroke.
|
||||
We're only interested in the input box value when the user hits the "Enter" key. We'd like to ignore all other keys.
|
||||
|
@ -118,7 +118,7 @@ figure.image-display
|
|||
img(src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## On blur
|
||||
|
||||
Our previous example won't transfer the current state of the input box if the user mouses away and clicks
|
||||
|
@ -130,7 +130,7 @@ figure.image-display
|
|||
+makeExample('user-input/ts/src/app/app.ts', 'key-up4-component')
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Put it all together
|
||||
We learned how to [display data](./displaying-data.html) in the previous chapter.
|
||||
We've acquired a small arsenal of event binding techniques in this chapter.
|
||||
|
@ -142,14 +142,14 @@ figure.image-display
|
|||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes")
|
||||
:markdown
|
||||
:marked
|
||||
Below is the entire "Little Tour of Heroes" micro-app in a single component.
|
||||
We'll call out the highlights after we bask briefly in its minimalist glory.
|
||||
<!--
|
||||
This example in http://plnkr.co/edit/JWeIqq
|
||||
-->
|
||||
+makeExample('user-input/ts/src/app/app.ts', 'little-tour-of-heroes-app')
|
||||
:markdown
|
||||
:marked
|
||||
We've seen almost everything here before. A few things are new or bear repeating.
|
||||
|
||||
### **Beware of camelCase variable names**
|
||||
|
@ -182,7 +182,7 @@ figure.image-display
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Next Steps
|
||||
|
||||
We've mastered the basic primitives for responding to user input and gestures.
|
||||
|
@ -194,4 +194,3 @@ figure.image-display
|
|||
in the `Forms` chapter.
|
||||
|
||||
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
include ../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Let's start from zero and build a super simple Angular 2 application in TypeScript.
|
||||
|
||||
.callout.is-helpful
|
||||
header Don't want TypeScript?
|
||||
:markdown
|
||||
: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
|
||||
:markdown
|
||||
:marked
|
||||
## The shortest, quickest ...
|
||||
|
||||
Let's put something on the screen in Angular 2 as quickly as we can.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
While we are about to describe steps to take on your development machine,
|
||||
you could take these same steps in an interactive, online coding environment
|
||||
such as [plunker](http://plnkr.co/ "Plunker"). You won't have to
|
||||
|
@ -25,21 +25,21 @@ include ../../../_includes/_util-fns
|
|||
If you like what you see - and we think you will - you can repeat this
|
||||
exercise on your own machine later.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
**Create a new folder** to hold our application project, perhaps like this:
|
||||
```
|
||||
mkdir angular2-quickstart
|
||||
cd angular2-quickstart
|
||||
```
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Our first Angular component
|
||||
|
||||
**Add a new file** called **`app.ts`** and paste the following lines:
|
||||
|
||||
+makeExample('quickstart/ts/src/app/app.ts', null, 'app.ts')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We've just defined an Angular 2 **component**,
|
||||
one of the most important Angular 2 features.
|
||||
Components are our primary means of creating application views
|
||||
|
@ -52,12 +52,12 @@ include ../../../_includes/_util-fns
|
|||
Above the class we see the `@Component` decoration.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The `@` symbol before the method name identifies `Component` as a decoration.
|
||||
A "decoration" is a TypeScript language feature
|
||||
for creating metadata about the class. Angular finds this metadata
|
||||
in the transpiled JavaScript and responds appropriately.
|
||||
:markdown
|
||||
:marked
|
||||
`@Component` tells Angular that this class *is an Angular component*.
|
||||
The configuration object passed to the `@Component` method has two
|
||||
field, a `selector` and a `template`.
|
||||
|
@ -81,7 +81,7 @@ include ../../../_includes/_util-fns
|
|||
We `import` exactly what we need, as we need it, from named file and library resources.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Add `index.html`
|
||||
|
||||
**Create** an `index.html` file.
|
||||
|
@ -90,7 +90,7 @@ include ../../../_includes/_util-fns
|
|||
|
||||
+makeExample('quickstart/ts/src/index.1.html', null, 'index.html')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We see three noteworthy sections of HTML:
|
||||
|
||||
1. We load JavaScript libraries from the web.
|
||||
|
@ -110,13 +110,13 @@ include ../../../_includes/_util-fns
|
|||
adorning our `AppComponent` class.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Run it!
|
||||
|
||||
We need a static file server to serve our application to the browser.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Don't have a static file server handy? Let's install one of our favorites
|
||||
called [live-server](https://www.npmjs.com/package/live-server "Live-server")
|
||||
with the **npm package manager**.
|
||||
|
@ -130,27 +130,27 @@ include ../../../_includes/_util-fns
|
|||
pre.prettyprint.lang-bash
|
||||
code npm install -g live-server
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Open a terminal window and enter
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code live-server
|
||||
:markdown
|
||||
:marked
|
||||
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
|
||||
Congratulations! We are in business.
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
:marked
|
||||
If you see `Loading...` displayed instead, see the
|
||||
[Browser ES6 support appendix](#es6support).
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What's wrong with this?
|
||||
|
||||
We were up and running in a hurry and we could explore Angular
|
||||
|
@ -177,7 +177,7 @@ include ../../../_includes/_util-fns
|
|||
We have tools and procedures for that.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Upping our game
|
||||
Let's take a few more steps to put our development on a better foundation. We will
|
||||
|
||||
|
@ -189,7 +189,7 @@ include ../../../_includes/_util-fns
|
|||
Shut down the `live-server` running in the terminal window (Ctrl-C) and proceed as follows.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Revise the application project structure
|
||||
|
||||
At the moment we're dumping everything into the "angular2-quickstart" **root folder**.
|
||||
|
@ -205,13 +205,13 @@ include ../../../_includes/_util-fns
|
|||
pre.prettyprint.lang-bash
|
||||
code mkdir src/app
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
In Windows:
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code mkdir src\app
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
**Move `index.html`** into the **`src`** folder.
|
||||
|
||||
**Move `app.ts`** into the **`src/app`** folder.
|
||||
|
@ -226,7 +226,7 @@ include ../../../_includes/_util-fns
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Install npm packages locally
|
||||
|
||||
We'll replace the web-based scripts in our `index.html` with
|
||||
|
@ -261,17 +261,17 @@ include ../../../_includes/_util-fns
|
|||
|
||||
+makeJson('quickstart/ts/package.json', { paths: 'name, version, dependencies, devDependencies'})
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
There is also a `scripts` section. **Find and replace** it with the following:
|
||||
|
||||
+makeJson('quickstart/ts/package.json', { paths: 'scripts'})
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We've just extended our project world with script commands
|
||||
that we'll be running very soon.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Update `index.html`
|
||||
|
||||
**Replace** the library scripts section with references to
|
||||
|
@ -279,13 +279,13 @@ include ../../../_includes/_util-fns
|
|||
|
||||
+makeExample('quickstart/ts/src/index.html', 'libraries')
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
**Update** the `System` configuration script as follows.
|
||||
|
||||
+makeExample('quickstart/ts/src/index.html', 'systemjs')
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
We won't be transpiling TypeScript in the browser anymore.
|
||||
We'll do that on our machine and ship the generated JavaScript
|
||||
files to the server.
|
||||
|
@ -297,19 +297,19 @@ include ../../../_includes/_util-fns
|
|||
|
||||
pre.prettyprint.lang-bash
|
||||
code import {Foo} from './app/foo'
|
||||
:markdown
|
||||
:marked
|
||||
`system.js`will know to look for a file named `foo.js` in the `src/app` folder.
|
||||
|
||||
That's exactly what we're doing in the last line. We're
|
||||
importing our main application file `app` (the generated `app.js` to be precise)
|
||||
from the `src/app/` folder (we moved it there, remember?)
|
||||
:markdown
|
||||
:marked
|
||||
Here's the final version
|
||||
|
||||
+makeExample('quickstart/ts/src/index.html', null, 'index.html')
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Prepare for TypeScript Compilation
|
||||
|
||||
### Add the TypeScript configuration file
|
||||
|
@ -322,12 +322,12 @@ include ../../../_includes/_util-fns
|
|||
+makeJson('quickstart/ts/src/tsconfig.json', null, 'tsconfig.json')
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
:marked
|
||||
See the [TypeScript configuration appendix](#tsconfig) to learn more about
|
||||
this file and these settings.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Final structure
|
||||
Our final project folder structure should look like this:
|
||||
```
|
||||
|
@ -342,7 +342,7 @@ include ../../../_includes/_util-fns
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Compile the TypeScript to JavaScript
|
||||
|
||||
We no longer transpile TypeScript to JavaScript in the browser.
|
||||
|
@ -353,7 +353,7 @@ include ../../../_includes/_util-fns
|
|||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
When it's done we should find the generated *app.js* file in the *src* folder and also an *app.map.js* file that
|
||||
helps debuggers navigate between the JavaScript and the TypeScript source.
|
||||
|
||||
|
@ -366,7 +366,7 @@ include ../../../_includes/_util-fns
|
|||
You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Run the app!
|
||||
|
||||
Now we are ready to see our app in action.
|
||||
|
@ -378,14 +378,14 @@ include ../../../_includes/_util-fns
|
|||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
**live-server** loads the browser for us, serves the HTML and JavaScript files,
|
||||
and displays our application message once more:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
### Make some changes
|
||||
**`live-server`** detects changes to our files and refreshes the browser page for us automatically.
|
||||
|
||||
|
@ -397,7 +397,7 @@ include ../../../_includes/_util-fns
|
|||
Keep `live-server` running in this terminal window. You can stop it anytime with `Ctrl-C`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What have we done?
|
||||
Our first application doesn't do much. It's basically "Hello, World" for Angular 2.
|
||||
|
||||
|
@ -428,7 +428,7 @@ include ../../../_includes/_util-fns
|
|||
|
||||
<!-- Move this to the Style Guide when we have one -->
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="tsconfig"></a>
|
||||
### Appendix: TypeScript configuration
|
||||
We added a TypeScript configuration file (`tsconfig.js`) to our project to
|
||||
|
@ -465,7 +465,7 @@ include ../../../_includes/_util-fns
|
|||
```
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
<a id="es6support"></a>
|
||||
### Appendix: Browser ES6 support
|
||||
Angular 2 requires ES6 support, such as can be found in most modern
|
||||
|
@ -478,7 +478,7 @@ include ../../../_includes/_util-fns
|
|||
code-example(language="sh" format=".").
|
||||
npm install es6-shim --save
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Now you can load the shim in your `index.html` before the other scripts:
|
||||
|
||||
code-example(language="html" format=".").
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We’ll need an Angular application to test, one as simple as possible while having all the angular features we want to test.
|
||||
|
||||
<!-- TODO We have such an app that you can download [here](./#). -->It’s a one-screen variation on the “Tour of Heroes” that should be familiar to you as a reader of this Developers Guide.
|
||||
|
@ -11,7 +11,7 @@ figure.image-display
|
|||
img(src='/resources/images/devguide/application-under-test/bongos-heroes.png'
|
||||
style="width:400px;" alt="Bongo's Heroes")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
At the top is a master list of heroes; at the bottom the detail for the current hero. Click a hero in the list to change the current hero. Change the name in the textbox and that name updates everywhere. The *Update* button modifies the `Hero.name` in an arbitrary way and that change also propagates everywhere on screen. The *Delete* button deletes the hero from the list and a new hero becomes current. *Refresh* clears both the list and detail, then restores the original list of heroes.
|
||||
|
||||
<!-- TODO You can see a short video of the app in action [here](./#) -->
|
||||
|
@ -33,6 +33,6 @@ figure.image-display
|
|||
We’ll examine the implementation details as we evolve our tests.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What’s Next?
|
||||
Now that we’re familiar with how the test app works, we’re ready to poke at it with our first application tests written in Jasmine.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
In this chapter we’ll setup the environment for testing our sample application and write a few easy Jasmine tests of the app’s simplest parts.
|
||||
We'll learn:
|
||||
- to test one of our application classes
|
||||
|
@ -10,7 +10,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Prior Knowledge
|
||||
:markdown
|
||||
:marked
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
|
@ -18,7 +18,7 @@ include ../../../../_includes/_util-fns
|
|||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Create the test-runner HTML
|
||||
|
||||
Step away from the Jasmine 101 folder and turn to the root folder of the application that we downloaded in the previous chapter.
|
||||
|
@ -47,7 +47,7 @@ include ../../../../_includes/_util-fns
|
|||
We’re picking up right where we left off. All we’ve done is change the title.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Update `package.json` for testing
|
||||
|
||||
We’ll assume that the application has `package.json` file that looks more or less like
|
||||
|
@ -61,7 +61,7 @@ pre.prettyprint.lang-bash
|
|||
|
||||
.alert.is-important Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>!
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Let’s make one more change to the `package.json` script commands.
|
||||
|
||||
**Open the `package.json` ** and scroll to the `scripts` node. Look for the command named `test`. Change it to:
|
||||
|
@ -71,7 +71,7 @@ pre.prettyprint.lang-bash
|
|||
That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## First app tests
|
||||
|
||||
Believe it or not … we could start testing *some* of our app right away. For example, we can test the `Hero` class:
|
||||
|
@ -135,7 +135,7 @@ pre.prettyprint.lang-bash
|
|||
The description should be sufficient to identify the tested application part and its source file. Almost any convention will do as long as you and your team follow it consistently and are never confused.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Run the tests
|
||||
|
||||
Open one terminal window and run the watching compiler command: `npm run tsc`
|
||||
|
@ -149,7 +149,7 @@ figure.image-display
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Critique
|
||||
|
||||
Is this `Hero` class even worth testing? It’s essentially a property bag with almost no logic. Maybe we should have tested the cloning feature. Maybe we should have tested id generation. We didn’t bother because there wasn’t much to learn by doing that.
|
||||
|
@ -161,7 +161,7 @@ figure.image-display
|
|||
We need to relocate these tests to a separate file. Let’s do that next.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Where do tests go?
|
||||
|
||||
Some people like to keep their tests in a `tests` folder parallel to the application source folder.
|
||||
|
@ -178,7 +178,7 @@ figure.image-display
|
|||
You may put your tests elsewhere if you wish. We’re putting ours inside the app, next to the source files that they test.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## First spec file
|
||||
|
||||
**Create** a new file, ** `hero.spec.ts` ** in `src/app` next to `hero.ts`.
|
||||
|
@ -187,7 +187,7 @@ figure.image-display
|
|||
|
||||
.alert.is-important All of our unit test files follow this .spec naming pattern.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Move the tests we just wrote in`unit-tests.html` to `hero.spec.ts` and convert them from JavaScript into TypeScript:
|
||||
|
||||
```
|
||||
|
@ -230,7 +230,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/first-app-tests/Jasmine-not-running-tests.png' style="width:400px;" alt="Jasmine not running any tests")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
That’s Jasmine saying “**things are _so_ bad that _I’m not running any tests_.**”
|
||||
|
||||
Open the browser’s Developer Tools (F12, Ctrl-Shift-i). There’s an error:
|
||||
|
@ -239,7 +239,7 @@ code-example(format="" language="html").
|
|||
Uncaught ReferenceError: exports is not defined
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Load tests with systemjs
|
||||
|
||||
The immediate cause of the error is the `export` statement in `hero.ts`.
|
||||
|
@ -296,7 +296,7 @@ figure.image-display
|
|||
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Observations
|
||||
|
||||
### System.config
|
||||
|
@ -326,7 +326,7 @@ figure.image-display
|
|||
Jasmine re-starts, this time with our imported test queued up.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What’s Next?
|
||||
We are able to test a part of our application with simple Jasmine tests.
|
||||
The part was a stand-alone class that made no mention or use of Angular.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We write **unit tests** to explore and confirm the **behavior** of parts of our application.
|
||||
|
||||
We like *having* unit tests for many reasons, three of them in particular:
|
||||
|
@ -22,7 +22,7 @@ include ../../../../_includes/_util-fns
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/unit-testing/spectrum.png' alt="Functional Testing Spectrum")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
<table style="box-shadow: none">
|
||||
<tr>
|
||||
<td style="border-bottom: none">Pure unit test</td>
|
||||
|
@ -113,12 +113,12 @@ figure.image-display
|
|||
|
||||
.callout.is-helpful
|
||||
header How to Use This Guide
|
||||
:markdown
|
||||
:marked
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
the [Tour of Heroes](../tutorial/) tutorial
|
||||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Let’s get started!
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We’ll write our tests with the [Jasmine test framework](http://jasmine.github.io/2.3/introduction.html).
|
||||
We’ll start by getting *some* tests to work - *any* tests at all.
|
||||
|
||||
|
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
**Create a new project folder** perhaps called `angular2-unit-testing`.
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Install npm packages locally
|
||||
|
||||
Next follow all of the steps prescribed in “Install npm packages locally” of the
|
||||
|
@ -24,19 +24,19 @@ pre.prettyprint.lang-bash
|
|||
code npm install jasmine-core --save-dev --save-exact
|
||||
|
||||
.alert.is-important
|
||||
:markdown
|
||||
:marked
|
||||
Be sure to install `jasmine-core` , not `jasmine`!
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
**Create a sub-folder `src` ** for our tests and then **cd into it**.
|
||||
|
||||
We are going to **display and control our tests in the browser**.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The browser is nice during development of a few tests. It’s not the best venue for working with a lot of tests and it won’t do at all for build automation. We’ll switch to the karma test-runner when the time comes. But the browser will do for now.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Create a new file called`unit-tests.html` and enter the following:
|
||||
```
|
||||
<html>
|
||||
|
@ -70,20 +70,20 @@ pre.prettyprint.lang-bash
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/jasmine-1-spec-0-failures.png' style="height:170px;" alt="Jasmine HTML test output")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
It doesn’t get much simpler than that!
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## First TypeScript Test
|
||||
Perhaps too simple. We won’t write our entire test suite inside one HTML file.
|
||||
Let’s **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Among Jasmine developers, a test is known as a “spec” and test filenames include the word “spec”. We’ll stick with that convention.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But let’s make it more modern with an arrow function:
|
||||
```
|
||||
it('true is true', () => expect(true).toEqual(true));
|
||||
|
@ -97,7 +97,7 @@ figure.image-display
|
|||
That’s a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Prepare for TypeScript
|
||||
|
||||
As we’ve seen before, we first have to tell the compiler how to compile our TypeScript files with
|
||||
|
@ -125,12 +125,12 @@ pre.prettyprint.lang-bash
|
|||
code npm run tsc
|
||||
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
:marked
|
||||
Our editor and the compiler may complain that they don’t know
|
||||
what `it` and `expect` are because they lack the typing files that describe Jasmine.
|
||||
We can ignore those annoying complaints for now as they are harmless.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
If we reload the browser, we should see the same Jasmine test-runner output as before.
|
||||
|
||||
We’ll be evolving these tests rapidly and it would be nice to have the browser refresh automatically as we make changes and recompile.
|
||||
|
@ -140,13 +140,13 @@ pre.prettyprint.lang-bash
|
|||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Now navigate to `1st-tests.html`
|
||||
|
||||
We should get the same Jasmine test-runner output as before.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Add a describe and another test
|
||||
|
||||
We can’t tell what file produced these test results. We only have one file at the moment but soon we’ll write more.
|
||||
|
@ -166,7 +166,7 @@ pre.prettyprint.lang-bash
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/test-report-1-spec-0-failures.png' style="height:100px;" alt="1 spec, 0 failures")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Let’s add another Jasmine test to `1st.spec.ts`
|
||||
```
|
||||
it('null is not the same thing as undefined',
|
||||
|
@ -178,23 +178,23 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-0-failures.png' style="height:100px;" alt="refreshed 2 specs, 0 failures")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
What does a failing test look like? Remove the `.not`. The browser refreshes and shows:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-1-failure.png' style="height:190px;" alt="failing test 2 specs, 1 failure")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Click the `Spec List` link just below “2 specs, 1 failure” to see the summary again:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/spec-list-2-specs-1-failure.png' style="height:140px;" alt="2 specs, 1 failure")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We can re-run just the failing test by double-clicking it. Try it!
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Debug the test
|
||||
Suppose we didn’t know what was going on. We can debug it in the browser.
|
||||
|
||||
|
@ -209,7 +209,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/jasmine-testing-101/null-to-equal-undefined.png' style="height:500px;" alt="null === undefined")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
How about that! They really aren’t equal.
|
||||
- remove the breakpoint (right-click in the “Breakpoints” section and chose “Remove breakpoint”)
|
||||
- Click the “play” icon to resume the test (or F8)
|
||||
|
@ -222,14 +222,14 @@ figure.image-display
|
|||
|
||||
<!-- TODO
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Learn more
|
||||
Learn more about basic Jasmine testing here
|
||||
[Resources TBD](./#)
|
||||
-->
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## What’s Next?
|
||||
Now that we’re familiar with Jasmine on its own, we’re ready to test an application.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We’ll test an Angular pipe in this chapter
|
||||
|
||||
An Angular pipe is a declarative way in HTML to transform some input into some displayable output.
|
||||
|
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
|
|||
code-example(format="linenums" language="html" escape="html").
|
||||
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
||||
|
||||
```
|
||||
|
@ -35,14 +35,14 @@ code-example(format="linenums" language="html" escape="html").
|
|||
|
||||
.callout.is-helpful
|
||||
header Prior Knowledge
|
||||
:markdown
|
||||
:marked
|
||||
The Unit Testing chapters build upon each other. We recommend reading them in order.
|
||||
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
|
||||
we introduced in the [QuickStart](../quickstart.html) and
|
||||
the [Tour of Heroes](../tutorial/) tutorial
|
||||
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
## Add the Angular library
|
||||
Looking back at `unit-tests.html` we realize that we have not loaded the Angular library.
|
||||
Yet we were able to load and test the application’s `Hero` class.
|
||||
|
@ -54,7 +54,7 @@ figure.image-display
|
|||
img(src='/resources/images/devguide/testing-an-angular-pipe/big-time-fail-screen.png'
|
||||
style="width:400px;" alt="Jasmine's' big time fail screen")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
If we then opened the browser’s Developer Tools (F12, Ctrl-Shift-I) and looked
|
||||
in the console window, we would see that SystemJS
|
||||
tried to load Angular and couldn't find it.
|
||||
|
@ -62,7 +62,7 @@ figure.image-display
|
|||
code-example(format="" language="html" escape="html").
|
||||
GET http://127.0.0.1:8080/src/angular2/angular2 404 (Not Found)
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We are writing an Angular application afterall and
|
||||
we were going to need Angular sooner or later. That time has come.
|
||||
The `InitCapsPiep` clearly depends on Angular as is clear in the first few lines:
|
||||
|
@ -147,7 +147,7 @@ figure.image-display
|
|||
img(src='/resources/images/devguide/testing-an-angular-pipe/5-specs-0-failures.png'
|
||||
style="width:400px;" alt="import promises 5 specs, 0 failures")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We have a pattern for adding new tests.
|
||||
|
||||
In future, when we add a new spec, we add another `System.import('app/some.spec')` to
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
# Tour of Heroes: the vision
|
||||
|
||||
Our grand plan is to build an app to help a staffing agency manage its stable of heroes.
|
||||
|
@ -25,7 +25,7 @@ include ../../../../_includes/_util-fns
|
|||
to chapters with greater depth.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## The End Game
|
||||
|
||||
Here's a visual idea of where we're going in this tour, beginning with the "Dashboard"
|
||||
|
@ -34,7 +34,7 @@ include ../../../../_includes/_util-fns
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Above the dashboard are two links ("Dashboard" and "Heroes").
|
||||
We could click them to navigate between this Dashboard and a Heroes view.
|
||||
|
||||
|
@ -44,7 +44,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/hero-details-1.png' alt="Details of hero in app")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Links at the top can take us to either of the main views.
|
||||
We'll click the "Back" button which sends us to the "Heroes" master list view with
|
||||
"Magneta" as the selected hero.
|
||||
|
@ -52,7 +52,7 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We click a different hero and the readonly mini-detail beneath the list reflects our new choice.
|
||||
|
||||
We click the "View Details" button to drill into the
|
||||
|
@ -63,14 +63,14 @@ figure.image-display
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Here's our app in action
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## How We Roll
|
||||
|
||||
We’ll build this Tour of Heroes together, step by step.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
# Once Upon a Time
|
||||
|
||||
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
|
||||
|
@ -22,32 +22,32 @@ include ../../../../_includes/_util-fns
|
|||
| └── tsconfig.json
|
||||
└── package.json
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
### Keep the app running
|
||||
Start the TypeScript compiler and have it watch for changes in one terminal window by typing
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Now open another terminal window and start the server by typing
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
This command starts the server, launches the app in a browser,
|
||||
and keeps the app running while we continue to build the Tour of Heroes.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
These two steps watch all project files. They recompile TypeScript files and re-run
|
||||
the app when any file changes.
|
||||
If the watchers fail to detect renamed or new files,
|
||||
stop these commands in each terminal by typing `CTRL+C` and then re-run them.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Show our Hero
|
||||
We want to display Hero data in our app
|
||||
|
||||
|
@ -61,12 +61,12 @@ include ../../../../_includes/_util-fns
|
|||
}
|
||||
```
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Now we update the template in the `@Component` decoration with data bindings to these new properties.
|
||||
|
||||
code-example(format="").
|
||||
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'
|
||||
:markdown
|
||||
:marked
|
||||
The browser should refresh and display our title and hero.
|
||||
|
||||
The double curly braces tell our app to read the `title` and `hero` properties from the component and render them.
|
||||
|
@ -103,7 +103,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
code-example(format="").
|
||||
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2>'
|
||||
:markdown
|
||||
:marked
|
||||
The browser refreshes and continues to display our hero’s name.
|
||||
|
||||
### Adding more HTML
|
||||
|
@ -112,7 +112,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
code-example(format="linenums").
|
||||
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2><div><label>id: </label>{{hero.id}}</div><div><label>name: </label>{{hero.name}}</div>'
|
||||
:markdown
|
||||
:marked
|
||||
Uh oh, our template string is getting long. We better take care of that to avoid the risk of making a typo in the template.
|
||||
|
||||
### Multi-line template strings
|
||||
|
@ -136,7 +136,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-important
|
||||
header A back-tick is not a single quote
|
||||
:markdown
|
||||
:marked
|
||||
**Be careful!** A back-tick (`) looks a lot like a single quote (').
|
||||
It's actually a completely different character.
|
||||
Back-ticks can do more than demarcate a string.
|
||||
|
@ -145,7 +145,7 @@ include ../../../../_includes/_util-fns
|
|||
is part of a single template string.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Editing Our Hero
|
||||
|
||||
We want to be able to edit the hero name in a textbox.
|
||||
|
@ -161,7 +161,7 @@ include ../../../../_includes/_util-fns
|
|||
<div><input value="{{hero.name}}" placeholder="name"></div>
|
||||
</div>
|
||||
`
|
||||
:markdown
|
||||
:marked
|
||||
We see in the browser that the hero’s name does appear in the `<input>` textbox.
|
||||
But something doesn’t feel right.
|
||||
When we change the name, we notice that our change
|
||||
|
@ -177,20 +177,20 @@ include ../../../../_includes/_util-fns
|
|||
Let’s update the template to use the **`ng-model`** built-in directive for two-way binding.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about `ng-model` in the [Template Syntax](../guide/template-syntax.html#ng-model)
|
||||
:markdown
|
||||
:marked
|
||||
Replace the `<input>` with the following HTML
|
||||
|
||||
code-example(language="html").
|
||||
<input [(ng-model)]="hero.name" placeholder="name">
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Unfortunately, that change broke our application and we're no longer displaying the hero in the browser.
|
||||
Let’s fix that next.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Declaring Template Directives
|
||||
|
||||
We added the `ng-model` directive but we didn't tell Angular about it.
|
||||
|
@ -218,7 +218,7 @@ include ../../../../_includes/_util-fns
|
|||
code-example(language="html").
|
||||
EXCEPTION: No value accessor for ' ' in [null]
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Apparently declaring the `NgModel` is not quite enough.
|
||||
|
||||
## Declare Multiple Form Directives
|
||||
|
@ -234,9 +234,9 @@ include ../../../../_includes/_util-fns
|
|||
bundled in a convenient array called `FORM_DIRECTIVES`.
|
||||
<!-- TODO
|
||||
.alert.is-helpful
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about Angular Forms in the [Forms chapter]()
|
||||
:markdown
|
||||
:marked
|
||||
-->
|
||||
Let’s forget about importing `NgModel` and import the `FORM_DIRECTIVES` array instead:
|
||||
```
|
||||
|
@ -259,7 +259,7 @@ include ../../../../_includes/_util-fns
|
|||
and plug that array into the `directives` property.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## The Road We’ve Travelled
|
||||
Let’s take stock of what we’ve built.
|
||||
|
||||
|
@ -306,7 +306,7 @@ include ../../../../_includes/_util-fns
|
|||
bootstrap(AppComponent);
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## The Road Ahead
|
||||
Our Tour of Heroes only displays one hero and we really want to display a list of heroes.
|
||||
We also want to allow the user to select a hero and display their details.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
# It Takes Many Heroes
|
||||
Our story needs more heroes.
|
||||
We’ll expand our Tour of Heroes app to display a list of heroes,
|
||||
|
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
|
|||
so we’ll need a way to do that.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Where We Left Off
|
||||
Before we continue with Part 2 of the Tour of Heroes,
|
||||
let’s verify we have the following structure after [Part 1](./toh-pt1.html).
|
||||
|
@ -27,24 +27,24 @@ include ../../../../_includes/_util-fns
|
|||
| ├── index.html
|
||||
| └── tsconfig.json
|
||||
└── package.json
|
||||
:markdown
|
||||
:marked
|
||||
### Keep the app running
|
||||
Start the TypeScript compiler and have it watch for changes in one terminal window by typing
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm run tsc
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Now open another terminal window and start the server by typing
|
||||
|
||||
pre.prettyprint.lang-bash
|
||||
code npm start
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
This will keep the application running while we continue to build the Tour of Heroes.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Displaying Our Heroes
|
||||
### Creating heroes
|
||||
Let’s create an array of ten heroes at the bottom of `app.ts`.
|
||||
|
@ -74,12 +74,12 @@ include ../../../../_includes/_util-fns
|
|||
```
|
||||
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
We could have defined the heroes list here in this component class.
|
||||
But we know that we’ll get the heroes from a data service.
|
||||
Because we know where we are heading, it makes sense to separate the hero data
|
||||
from the class implementation from the start.
|
||||
:markdown
|
||||
:marked
|
||||
### Displaying heroes in a template
|
||||
Our component has`heroes`. Let’s create an unordered list in our template to display them.
|
||||
We’ll insert the following chunk of HTML below the title and above the hero details.
|
||||
|
@ -104,11 +104,11 @@ include ../../../../_includes/_util-fns
|
|||
<li *ng-for="#hero of heroes">
|
||||
```
|
||||
.alert.is-critical
|
||||
:markdown
|
||||
:marked
|
||||
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
The (`*`) prefix to `ng-for` indicates that the `<li>` element and its children
|
||||
constitute a master template.
|
||||
|
||||
|
@ -125,7 +125,7 @@ include ../../../../_includes/_util-fns
|
|||
Learn more about `ng-for` and local template variables in the
|
||||
[Template Syntax](../guide/template-syntax.html#ng-for) chapter.
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
With this background in mind, we now insert some content between the `<li>` tags
|
||||
that uses the `hero` template variable to display the hero’s properties.
|
||||
|
||||
|
@ -134,7 +134,7 @@ include ../../../../_includes/_util-fns
|
|||
<span class="badge">{{hero.id}}</span> {{hero.name}}
|
||||
</li>
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
### Declaring ng-for
|
||||
When we view the running app in the browser we see nothing … no heroes.
|
||||
We open the developer tools and see an error in the console.
|
||||
|
@ -144,7 +144,7 @@ include ../../../../_includes/_util-fns
|
|||
Can't bind to 'ngForOf' since it isn't a known property of the '<template>' element and
|
||||
there are no matching directives with a corresponding property
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Thankfully we have a clear error message that indicates where we went wrong.
|
||||
We used `ng-for` in the template but we didn’t tell the component about it.
|
||||
From Angular's perspective, `ng-for` is a meaningless attribute.
|
||||
|
@ -200,14 +200,14 @@ include ../../../../_includes/_util-fns
|
|||
<span class="badge">{{hero.id}}</span> {{hero.name}}
|
||||
</li>
|
||||
</ul>
|
||||
:markdown
|
||||
:marked
|
||||
Our styled list of heroes should look like this:
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app (no selection color)")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Selecting a Hero
|
||||
We have a list of heroes and we have a single hero displayed in our app.
|
||||
The list and the single hero are not connected in any way.
|
||||
|
@ -224,19 +224,19 @@ include ../../../../_includes/_util-fns
|
|||
<li *ng-for="#hero of heroes" (click)="onSelect(hero)">
|
||||
<span class="badge">{{hero.id}}</span> {{hero.name}}
|
||||
</li>
|
||||
:markdown
|
||||
:marked
|
||||
Focus on the event binding
|
||||
pre.prettyprint.lang-bash
|
||||
code (click)="onSelect(hero)">
|
||||
:markdown
|
||||
:marked
|
||||
The parenthesis identify the `<li>` element’s `click` event as the target.
|
||||
The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`,
|
||||
passing the local template variable `hero` as an argument.
|
||||
That’s the same `hero` variable we defined previously in the `ng-for`.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about Event Binding in the [Templating Syntax](../guide/template-syntax.html#event-binding) chapter.
|
||||
:markdown
|
||||
:marked
|
||||
### Add the click handler
|
||||
Our event binding refers to an `onSelect` method that doesn’t exist yet.
|
||||
We’ll add that method to our component now.
|
||||
|
@ -271,7 +271,7 @@ include ../../../../_includes/_util-fns
|
|||
<input [(ng-model)]="selectedHero.name" placeholder="name"></input>
|
||||
</div>
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
### Hide the empty detail with ng-if
|
||||
|
||||
When our app loads we see a list of heroes, but a hero is not selected.
|
||||
|
@ -281,7 +281,7 @@ include ../../../../_includes/_util-fns
|
|||
code-example(language="html").
|
||||
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Remember that we are displaying `selectedHero.name` in the template.
|
||||
This name property does not exist because `selectedHero`itself is undefined.
|
||||
|
||||
|
@ -300,17 +300,17 @@ include ../../../../_includes/_util-fns
|
|||
</div>
|
||||
</div>
|
||||
.alert.is-critical
|
||||
:markdown
|
||||
:marked
|
||||
Remember that the leading asterisk (`*`) in front of `ng-if` is
|
||||
a critical part of this syntax.
|
||||
:markdown
|
||||
:marked
|
||||
When there is no `selectedHero`, the `ng-if` directive removes the hero detail HTML from the DOM.
|
||||
There will be no hero detail elements and no bindings to worry about.
|
||||
|
||||
When the user picks a hero, `selectedHero` becomes "truthy" and
|
||||
`ng-if` puts the hero detail content into the DOM and evaluates the nested bindings.
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
`ng-if` and `ng-for` are called “structural directives” because they can change the
|
||||
structure of portions of the DOM.
|
||||
In other words, they give structure to the way Angular displays content in the DOM.
|
||||
|
@ -318,7 +318,7 @@ include ../../../../_includes/_util-fns
|
|||
Learn more about `ng-if`, `ng-for` and other structural directives in the
|
||||
[Template Syntax](../guide/template-syntax.html#directives) chapter
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We learned previously with `NgFor` that we must declare every directive we use in the component’s `@Component` decorator.
|
||||
Let’s do that again for `NgIf`.
|
||||
|
||||
|
@ -327,7 +327,7 @@ include ../../../../_includes/_util-fns
|
|||
```
|
||||
import {bootstrap, Component, FORM_DIRECTIVES, NgFor, NgIf} from 'angular2/angular2';
|
||||
```
|
||||
:markdown
|
||||
:marked
|
||||
Now add `NgIf` to the directives array in the `@Component` decorator:
|
||||
```
|
||||
directives: [FORM_DIRECTIVES, NgFor, NgIf]
|
||||
|
@ -346,7 +346,7 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="Selected hero")
|
||||
:markdown
|
||||
:marked
|
||||
First we’ll add a `getSelectedClass` method to the component that compares the current `selectedHero` to a hero parameter
|
||||
and returns an object with a single key/value pair.
|
||||
|
||||
|
@ -371,17 +371,17 @@ include ../../../../_includes/_util-fns
|
|||
<span class="badge">{{hero.id}}</span> {{hero.name}}
|
||||
</li>
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
Notice in the template that the `ng-class` name is surrounded in square brackets (`[]`).
|
||||
This is the syntax for a Property Binding, a binding in which data flows one way
|
||||
from the data source (the `getSelectedClass`) to a property of the `ng-class` directive.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
Learn more about [ng-class](../guide/template-syntax.html#ng-class)
|
||||
and [Property Binding](../guide/template-syntax.html#property-binding)
|
||||
in the Template Syntax chapter
|
||||
:markdown
|
||||
:marked
|
||||
We've added yet another new directive to our template that we have to import and declare
|
||||
in the component’s `directives` array as we’ve done twice before.
|
||||
```
|
||||
|
@ -398,7 +398,7 @@ include ../../../../_includes/_util-fns
|
|||
figure.image-display
|
||||
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app")
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
We select a different hero and the tell-tale color switches to that hero.
|
||||
|
||||
## Declaring Built-In Directives
|
||||
|
@ -427,7 +427,7 @@ include ../../../../_includes/_util-fns
|
|||
Cleaner code for the win!
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## The Road We’ve Travelled
|
||||
Here’s what we achieved in this chapter:
|
||||
|
||||
|
@ -439,4 +439,3 @@ include ../../../../_includes/_util-fns
|
|||
Our Tour of Heroes has grown, but it’s far from complete.
|
||||
We want to get data from an asynchronous source using promises, use shared services, and create reusable components.
|
||||
We’ll learn more about these tasks in the coming tutorial chapters.
|
||||
|
|
@ -22,14 +22,14 @@ module.exports = function(encodeCodeBlock) {
|
|||
newLines.pop();
|
||||
} else {
|
||||
// wierd case - first expression in str is an @example
|
||||
// in this case the :markdown appear above the str passed in,
|
||||
// in this case the :marked appear above the str passed in,
|
||||
// so we need to put 'something' into the markdown tag.
|
||||
newLines.push(sp + "."); // '.' is a dummy char
|
||||
}
|
||||
}
|
||||
newLines.push(spMixin + line);
|
||||
// after a mixin line we need to reenter markdown.
|
||||
newLines.push(spMixin + ':markdown');
|
||||
newLines.push(spMixin + ':marked');
|
||||
isAfterMarkdownTag = true;
|
||||
} else {
|
||||
if ((!isAfterMarkdownTag) || (line.trim().length > 0)) {
|
||||
|
|
|
@ -14,7 +14,7 @@ p.location-badge.
|
|||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
{%- if doc.notYetDocumented %}
|
||||
*Not Yet Documented*
|
||||
{% else %}
|
||||
|
@ -43,7 +43,7 @@ p.location-badge.
|
|||
pre.prettyprint
|
||||
code.
|
||||
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.parameters) | indent(8, false) | trim $}
|
||||
:markdown
|
||||
:marked
|
||||
{$ doc.constructorDoc.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
|
||||
{% endif -%}
|
||||
|
||||
|
@ -54,7 +54,7 @@ p.location-badge.
|
|||
code.
|
||||
{$ member.name $}{$ paramList(member.parameters) | indent(8, false) | trim $}{$ returnType(member.returnType) $}
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
{$ member.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
|
||||
|
||||
{% endif %}{% endfor %}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
code {$ property.bindingName | dashCase $}
|
||||
| bound to
|
||||
code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $}
|
||||
:markdown
|
||||
:marked
|
||||
{$ property.memberDoc.description | indentForMarkdown(2) | trimBlankLines $}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
|||
code {$ property.bindingName | dashCase $}
|
||||
| bound to
|
||||
code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $}
|
||||
:markdown
|
||||
:marked
|
||||
{$ event.memberDoc.description | indentForMarkdown(2) | trimBlankLines $}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
|
@ -14,7 +14,7 @@ include ../../_util-fns
|
|||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
{$ doc.description | indentForMarkdown(4) | trimBlankLines $}
|
||||
|
||||
{% endblock %}
|
|
@ -14,7 +14,7 @@ include ../../_util-fns
|
|||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
:marked
|
||||
{%- if doc.notYetDocumented %}
|
||||
### *Not Yet Documented*
|
||||
{% else %}
|
||||
|
|
|
@ -49,7 +49,7 @@ module.exports = function convertBackticksToCodeBlocks() {
|
|||
// modulo op in next line insures that pad is always a multiple of 2 ( jade whitespace).
|
||||
postPad = postPad.substr(2 + (postPad.length % 2)); // exdent
|
||||
}
|
||||
replaceVal = replaceVal + postPad + ':markdown\n';
|
||||
replaceVal = replaceVal + postPad + ':marked\n';
|
||||
}
|
||||
doc.renderedContent = doc.renderedContent.replace(entireBlock, replaceVal);
|
||||
captures = BACKTICK_CAPTURE.exec(doc.renderedContent);
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('convertBackticksToCodeBlocks', function() {
|
|||
'export class TypeScriptClass {\n' +
|
||||
'}\n' +
|
||||
'\n' +
|
||||
':markdown\n' +
|
||||
':marked\n' +
|
||||
'postamble\n'
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Install Angular2
|
||||
There are four steps to create any Angular app:
|
||||
|
||||
|
@ -19,14 +19,14 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Typescript vs ES5
|
||||
:markdown
|
||||
:marked
|
||||
Although we work through the examples in TypeScript, you can also use
|
||||
regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript
|
||||
version. Note that in ES5, you'd want to name your files `.js` rather than
|
||||
`.ts`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Create an entry point
|
||||
Create an `index.html` file and add the Angular library tags and a `main.ts` file where
|
||||
you'll build your first component.
|
||||
|
@ -40,12 +40,12 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Don't use code.angularjs.org in a live app
|
||||
:markdown
|
||||
:marked
|
||||
This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is
|
||||
fine for examples, but you'd want to serve it yourself or use a CDN for real deployment.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Set up the starting component
|
||||
|
||||
In `main.ts`, create a class called `AppComponent`, configure it to bind to the
|
||||
|
@ -56,14 +56,14 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Annotations vs Decorators
|
||||
:markdown
|
||||
:marked
|
||||
If you are transpiling using a tool that translates the `@` symbols to
|
||||
annotations (for example Traceur), you will need to import the annotation versions of
|
||||
Component and View. That can be easily achieved using
|
||||
`import {ComponentAnnotation as Component, ViewAnnotation as View}`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Run it!
|
||||
|
||||
Open `index.html` through your web server and you should see:
|
||||
|
@ -72,13 +72,13 @@ include ../../../../_includes/_util-fns
|
|||
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Explanations
|
||||
|
||||
This basic Angular app contains the structure for any app you'll build.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### It's all a tree
|
||||
|
||||
You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top
|
||||
|
@ -94,7 +94,7 @@ include ../../../../_includes/_util-fns
|
|||
these in the following pages.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### @Component and @View annotations
|
||||
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`).
|
||||
|
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
|
|||
The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### import vs. window.angular
|
||||
|
||||
The main difference between the ES5 and TypeScript versions is the loading of modules.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
include ../../../../_includes/_util-fns
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Install Angular2
|
||||
There are four steps to create any Angular app:
|
||||
|
||||
|
@ -19,14 +19,14 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Typescript vs ES5
|
||||
:markdown
|
||||
:marked
|
||||
Although we work through the examples in TypeScript, you can also use
|
||||
regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript
|
||||
version. Note that in ES5, you'd want to name your files `.js` rather than
|
||||
`.ts`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Create an entry point
|
||||
Create an `index.html` file and add the Angular library tags and a `main.ts` file where
|
||||
you'll build your first component.
|
||||
|
@ -40,12 +40,12 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Don't use code.angularjs.org in a live app
|
||||
:markdown
|
||||
:marked
|
||||
This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is
|
||||
fine for examples, but you'd want to serve it yourself or use a CDN for real deployment.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Set up the starting component
|
||||
|
||||
In `main.ts`, create a class called `AppComponent`, configure it to bind to the
|
||||
|
@ -56,14 +56,14 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
.callout.is-helpful
|
||||
header Annotations vs Decorators
|
||||
:markdown
|
||||
:marked
|
||||
If you are transpiling using a tool that translates the `@` symbols to
|
||||
annotations (for example Traceur), you will need to import the annotation versions of
|
||||
Component and View. That can be easily achieved using
|
||||
`import {ComponentAnnotation as Component, ViewAnnotation as View}`.
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Run it!
|
||||
|
||||
Open `index.html` through your web server and you should see:
|
||||
|
@ -72,13 +72,13 @@ include ../../../../_includes/_util-fns
|
|||
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
|
||||
|
||||
.l-main-section
|
||||
:markdown
|
||||
:marked
|
||||
## Explanations
|
||||
|
||||
This basic Angular app contains the structure for any app you'll build.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### It's all a tree
|
||||
|
||||
You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top
|
||||
|
@ -94,7 +94,7 @@ include ../../../../_includes/_util-fns
|
|||
these in the following pages.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### @Component and @View annotations
|
||||
|
||||
A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`).
|
||||
|
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
|
|||
The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file.
|
||||
|
||||
.l-sub-section
|
||||
:markdown
|
||||
:marked
|
||||
### import vs. window.angular
|
||||
|
||||
The main difference between the ES5 and TypeScript versions is the loading of modules.
|
||||
|
|
Loading…
Reference in New Issue