docs(attribute-directives): code shuffle & alpha52 update

closes #473
This commit is contained in:
Ward Bell 2015-12-10 20:27:41 -08:00
parent dbc3982aae
commit 47d12c896f
12 changed files with 68 additions and 70 deletions

View File

@ -1,4 +1,4 @@
<!-- #docregion --> <!-- #docregion -->
<h1>My First Attribute Directive</h1> <h1>My First Attribute Directive</h1>
<span my-highlight>Highlight me!</span> <span myHighlight>Highlight me!</span>
<!-- #enddocregion --> <!-- #enddocregion -->

View File

@ -9,12 +9,12 @@
</div> </div>
<!-- #docregion span --> <!-- #docregion span -->
<p><span [my-highlight]="color">Highlight me!</span></p> <p><span [myHighlight]="color">Highlight me!</span></p>
<!-- #enddocregion span --> <!-- #enddocregion span -->
<!-- #enddocregion v2 --> <!-- #enddocregion v2 -->
<!-- #docregion defaultColor --> <!-- #docregion defaultColor -->
<p><span [my-highlight]="color" [default-color]="'violet'"> <p><span [myHighlight]="color" [defaultColor]="'violet'">
Highlight me too! Highlight me too!
</span></p> </span></p>
<!-- #enddocregion defaultColor --> <!-- #enddocregion defaultColor -->

View File

@ -1,5 +1,5 @@
// #docregion // #docregion
import {Component} from 'angular2/angular2'; import {Component} from 'angular2/core';
import {Highlight} from './highlight.directive' import {Highlight} from './highlight.directive'
@Component({ @Component({

View File

@ -1,5 +1,5 @@
// #docregion // #docregion
import {bootstrap} from 'angular2/angular2'; import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component'; import {AppComponent} from './app.component';
bootstrap(AppComponent); bootstrap(AppComponent);

View File

@ -1,14 +1,14 @@
// #docregion // #docregion
import {Directive, ElementRef, Renderer, Input} from 'angular2/angular2'; import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
@Directive({ @Directive({
selector: '[my-highlight]' selector: '[myHighlight]'
}) })
export class Highlight { export class Highlight {
constructor(el: ElementRef, renderer: Renderer) { constructor(el: ElementRef, renderer: Renderer) {
//el.nativeElement.style.backgroundColor = 'yellow'; //el.nativeElement.style.backgroundColor = 'yellow';
renderer.setElementStyle(el, 'background-color', 'yellow'); renderer.setElementStyle(el, 'backgroundColor', 'yellow');
} }
} }
// #enddocregion // #enddocregion

View File

@ -1,8 +1,8 @@
// #docregion // #docregion
import {Directive, ElementRef, Renderer, Input} from 'angular2/angular2'; import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
@Directive({ @Directive({
selector: '[my-highlight]', selector: '[myHighlight]',
// #docregion host // #docregion host
host: { host: {
'(mouseenter)': 'onMouseEnter()', '(mouseenter)': 'onMouseEnter()',
@ -22,7 +22,7 @@ export class Highlight {
onMouseLeave() { this._highlight(null); } onMouseLeave() { this._highlight(null); }
private _highlight(color: string) { private _highlight(color: string) {
this.renderer.setElementStyle(this.el, 'background-color', color); this.renderer.setElementStyle(this.el, 'backgroundColor', color);
} }
// #enddocregion mouse-methods // #enddocregion mouse-methods

View File

@ -1,9 +1,9 @@
// #docplaster // #docplaster
// #docregion full // #docregion full
import {Directive, ElementRef, Renderer, Input} from 'angular2/angular2'; import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
@Directive({ @Directive({
selector: '[my-highlight]', selector: '[myHighlight]',
host: { host: {
'(mouseenter)': 'onMouseEnter()', '(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()' '(mouseleave)': 'onMouseLeave()'
@ -22,7 +22,7 @@ export class Highlight {
// #docregion full // #docregion full
// #docregion class-1 // #docregion class-1
// #docregion color // #docregion color
@Input('my-highlight') highlightColor: string; @Input('myHighlight') highlightColor: string;
// #enddocregion color // #enddocregion color
private _defaultColor = 'red'; private _defaultColor = 'red';
@ -42,7 +42,7 @@ export class Highlight {
onMouseLeave() { this._highlight(null); } onMouseLeave() { this._highlight(null); }
private _highlight(color:string) { private _highlight(color:string) {
this.renderer.setElementStyle(this.el, 'background-color', color); this.renderer.setElementStyle(this.el, 'backgroundColor', color);
} }
} }
// #enddocregion class-1 // #enddocregion class-1

View File

@ -4,8 +4,8 @@
<head> <head>
<title>Attribute Directives</title> <title>Attribute Directives</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script> <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script> <script>
System.config({ System.config({
packages: {'app': {defaultExtension: 'js'}} packages: {'app': {defaultExtension: 'js'}}

View File

@ -4,18 +4,12 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"tsc": "tsc -p src -w", "tsc": "tsc",
"start": "live-server --open=src" "tsc:w": "tsc -w",
"lite": "lite-server",
"both": "concurrent \"npm run tsc:w\" \"npm run lite\" "
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC"
"dependencies": {
"angular2": "2.0.0-alpha.47",
"systemjs": "0.19.6"
},
"devDependencies": {
"live-server": "^0.8.2",
"typescript": "^1.7.3"
}
} }

View File

@ -1,12 +1,16 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES5", "target": "ES5",
"module": "commonjs", "module": "system",
"moduleResolution": "node",
"sourceMap": true, "sourceMap": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"removeComments": false, "removeComments": false,
"noImplicitAny": true, "noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true "suppressImplicitAnyIndexErrors": true
} },
"exclude": [
"node_modules"
]
} }

View File

@ -10,7 +10,7 @@ include ../../../../_includes/_util-fns
* respond to user-initiated events * respond to user-initiated events
* pass values into the directive using data binding * pass values into the directive using data binding
[Live Example](/resources/live-examples/attribute-directives/ts/src/plnkr.html) [Live Example](/resources/live-examples/attribute-directives/ts/plnkr.html)
## Directives overview ## Directives overview
@ -59,7 +59,7 @@ include ../../../../_includes/_util-fns
As in the [tutorial](/docs/ts/latest/tutorial/), we'll rename `app.ts` to `app.component.ts` As in the [tutorial](/docs/ts/latest/tutorial/), we'll rename `app.ts` to `app.component.ts`
and relocate the call to `bootstrap` to a separate `boot.ts` file. and relocate the call to `bootstrap` to a separate `boot.ts` file.
+makeExample('attribute-directives/ts/src/app/boot.ts', null, 'app/boot.ts') +makeExample('attribute-directives/ts/app/boot.ts', null, 'app/boot.ts')
:marked :marked
A clean `app.component.ts` without bootstrapping is much easer to test. A clean `app.component.ts` without bootstrapping is much easer to test.
@ -70,7 +70,7 @@ code-example.
:marked :marked
### Write the directive ### Write the directive
Add a new file to the `app` folder called `highlight.directive.ts` and add the following code: Add a new file to the `app` folder called `highlight.directive.ts` and add the following code:
+makeExample('attribute-directives/ts/src/app/highlight.directive.1.ts', null, 'app/highlight.directive.ts') +makeExample('attribute-directives/ts/app/highlight.directive.1.ts', null, 'app/highlight.directive.ts')
:marked :marked
We begin by importing some symbols from the Angular library. We begin by importing some symbols from the Angular library.
@ -86,17 +86,17 @@ code-example.
The [css selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) The [css selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
is the attribute name in square brackets. is the attribute name in square brackets.
Our directive's selector is `[my-highlight]`. Our directive's selector is `[myHighlight]`.
Angular will locate all elements in the template that have an attribute named `my-highlight`. Angular will locate all elements in the template that have an attribute named `myHighlight`.
.l-sub-section .l-sub-section
:marked :marked
### Why not call it "highlight"? ### Why not call it "highlight"?
*highlight* is a nicer name than *my-highlight* and, technically, it would work if we called it that. *highlight* is a nicer name than *myHighlight* and, technically, it would work if we called it that.
However, the good folks at Angular strongly prefer hyphenated directive selector names. However, the good folks at Angular strongly prefer hyphenated directive selector names.
The HTML standards body will never name one of its attributes with a hyphen and there is The HTML standards body will never name one of its attributes with a hyphen and there is
less risk of colliding with a third-party directive name when we give ours a prefix. less risk of colliding with a third-party directive name when we give ours a prefix.
The `ng-` prefix belongs to Angular. The `ng` prefix belongs to Angular.
We need a prefix of our own, preferably short, and `my-` will do for now. We need a prefix of our own, preferably short, and `my` will do for now.
:marked :marked
After the `@Component` metadata comes the directive's controller class which we are exporting After the `@Component` metadata comes the directive's controller class which we are exporting
to make it accessible to other components. to make it accessible to other components.
@ -140,17 +140,17 @@ code-example.
In Angular terms, the `<span>` element will be the attribute **host**. In Angular terms, the `<span>` element will be the attribute **host**.
We'll put the template in its own `app.component.html` file that looks like this: We'll put the template in its own `app.component.html` file that looks like this:
+makeExample('attribute-directives/ts/src/app/app.component.1.html',null,'app/app.component.html') +makeExample('attribute-directives/ts/app/app.component.1.html',null,'app/app.component.html')
:marked :marked
A separate template file is clearly overkill for a 2-line template. A separate template file is clearly overkill for a 2-line template.
Hang in there; we're going to expand it later. Hang in there; we're going to expand it later.
Meanwhile, we'll revise the `AppComponent` to reference this template. Meanwhile, we'll revise the `AppComponent` to reference this template.
+makeExample('attribute-directives/ts/src/app/app.component.ts',null,'app/app.component.ts') +makeExample('attribute-directives/ts/app/app.component.ts',null,'app/app.component.ts')
:marked :marked
We've added an `import` statement to fetch the 'Highlight' directive and We've added an `import` statement to fetch the 'Highlight' directive and
added that class to a `directives` array in the component metadata so that Angular added that class to a `directives` array in the component metadata so that Angular
will recognize our directive when it encounters `my-highlight` in the template. will recognize our directive when it encounters `myHighlight` in the template.
Angular would simply ignore the `my-highlight` attribute without it. Angular would simply ignore the `myHighlight` attribute without it.
We run the app and see that our directive highlights the span text. We run the app and see that our directive highlights the span text.
@ -159,7 +159,7 @@ figure.image-display
:marked :marked
Let's recap what happened. Let's recap what happened.
Angular found the `my-highlight` attribute on the `<span>` element. It created Angular found the `myHighlight` attribute on the `<span>` element. It created
an instance of the `Highlight` directive class, an instance of the `Highlight` directive class,
injecting both a reference to the element and the `Renderer` service into the constructor. injecting both a reference to the element and the `Renderer` service into the constructor.
The constructor told the `Renderer` to set the `<span>` element's background style to yellow. The constructor told the `Renderer` to set the `<span>` element's background style to yellow.
@ -179,7 +179,7 @@ figure.image-display
Start with event detection. Start with event detection.
We add a `host` property to the directive metadata and give it a configuration object We add a `host` property to the directive metadata and give it a configuration object
that specifies two mouse events and the directive methods to call when they are raised. that specifies two mouse events and the directive methods to call when they are raised.
+makeExample('attribute-directives/ts/src/app/highlight.directive.2.ts','host') +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','host')
:marked :marked
.l-sub-section .l-sub-section
:marked :marked
@ -196,7 +196,7 @@ figure.image-display
Let's roll with the `host` property. Let's roll with the `host` property.
:marked :marked
Now we implement those two mouse event handlers: Now we implement those two mouse event handlers:
+makeExample('attribute-directives/ts/src/app/highlight.directive.2.ts','mouse-methods') +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','mouse-methods')
:marked :marked
Notice that they delegate to a helper method that calls the `Renderer` service Notice that they delegate to a helper method that calls the `Renderer` service
as we used to do in the constructor. as we used to do in the constructor.
@ -205,10 +205,10 @@ figure.image-display
we still want the injected `ElementRef` and `Renderer` service. we still want the injected `ElementRef` and `Renderer` service.
We revise the constructor signature to capture the injectables in private variables We revise the constructor signature to capture the injectables in private variables
and clear the body. and clear the body.
+makeExample('attribute-directives/ts/src/app/highlight.directive.2.ts','ctor') +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')
:marked :marked
Here's the updated directive: Here's the updated directive:
+makeExample('attribute-directives/ts/src/app/highlight.directive.2.ts',null, 'app/highlight.directive.ts') +makeExample('attribute-directives/ts/app/highlight.directive.2.ts',null, 'app/highlight.directive.ts')
:marked :marked
We run the app and confirm that the background color appears as we move the mouse over the `span` and We run the app and confirm that the background color appears as we move the mouse over the `span` and
disappears as we move out. disappears as we move out.
@ -221,49 +221,50 @@ figure.image-display
Currently the highlight color is hard-coded within the directive. That's inflexible. Currently the highlight color is hard-coded within the directive. That's inflexible.
We should set the highlight color externally with a binding like this: We should set the highlight color externally with a binding like this:
+makeExample('attribute-directives/ts/src/app/app.component.html','span') +makeExample('attribute-directives/ts/app/app.component.html','span')
:marked :marked
We'll extend our directive class with a bindable **input** `highlightColor` property and use it when we highlight text. We'll extend our directive class with a bindable **input** `highlightColor` property and use it when we highlight text.
Here is the final version of the class: Here is the final version of the class:
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'class-1', 'app/highlight.directive.ts (class only)') +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'class-1', 'app/highlight.directive.ts (class only)')
:marked :marked
The new `highlightColor` property is called an "input" property because data flows from the binding expression into our directive. The new `highlightColor` property is called an "input" property because data flows from the binding expression into our directive.
Notice that we call the `@Input()` decorator function while defining the property. Notice that we call the `@Input()` decorator function while defining the property.
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'color') +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'color')
:marked :marked
This `@Input` decorator adds metadata to the class that makes the `highlightColor` property available for property binding This `@Input` decorator adds metadata to the class that makes the `highlightColor` property available for property binding
under the `my-highlight` alias. under the `myHighlight` alias.
We must add this input metadata. Angular will give us an error if we try to bind We must add this input metadata. Angular will give us an error if we try to bind
to a property without declaring it as an input. to a property without declaring it as an input.
.l-sub-section .l-sub-section
:marked :marked
The developer who uses our directive expects to bind to the attribute name, `my-highlight`. The developer who uses our directive expects to bind to the attribute name, `myHighlight`.
The directive property name is `highlightColor`. That's a disconnect. The directive property name is `highlightColor`. That's a disconnect.
We can resolve the discrepancy by renaming the property to `myHighlight` and define it as follows: We can resolve the discrepancy by renaming the property to `myHighlight` and define it as follows:
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'highlight') +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'highlight')
<br> <br>
:marked :marked
We don't like that property name. Maybe we don't want that property name inside the directive perhaps because it
We prefer, in this case, to **alias** the `highlightColor` property with the attribute name by doesn't express our intention well.
passing `my-highlight` into the `@Input` decorator: We can **alias** the `highlightColor` property with the attribute name by
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'color') passing `myHighlight` into the `@Input` decorator:
+makeExample('attribute-directives/ts/app/highlight.directive.ts', 'color')
:marked :marked
Now that we're getting the highlight color as an input, we modify the `onMouseEnter()` method to use Now that we're getting the highlight color as an input, we modify the `onMouseEnter()` method to use
it instead of the hard-coded color name. it instead of the hard-coded color name.
We also define a red default color as a fallback in case We also define a red default color as a fallback in case
the user neglects to bind with a color. the user neglects to bind with a color.
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'mouse-enter') +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'mouse-enter')
:marked :marked
Now we'll update our `AppComponent` template to let Now we'll update our `AppComponent` template to let
users pick the highlight color and bind their choice to our directive. users pick the highlight color and bind their choice to our directive.
Here is the updated template: Here is the updated template:
+makeExample('attribute-directives/ts/src/app/app.component.html', 'v2') +makeExample('attribute-directives/ts/app/app.component.html', 'v2')
.l-sub-section .l-sub-section
:marked :marked
@ -294,12 +295,12 @@ figure.image-display
Let's let the template developer set the default color, the color that prevails until the user picks a highlight color. Let's let the template developer set the default color, the color that prevails until the user picks a highlight color.
We'll add a second **input** property to `HighlightDirective` called `defaultColor`: We'll add a second **input** property to `HighlightDirective` called `defaultColor`:
+makeExample('attribute-directives/ts/src/app/highlight.directive.ts', 'defaultColor') +makeExample('attribute-directives/ts/app/highlight.directive.ts', 'defaultColor')
:marked :marked
The `defaultColor` property has a setter that overrides the hard-coded default color, "red". The `defaultColor` property has a setter that overrides the hard-coded default color, "red".
We don't need a getter. We don't need a getter.
How do we bind to it? We already "burned" the `my-highlight` attribute name as a binding target. How do we bind to it? We already "burned" the `myHighlight` attribute name as a binding target.
Remember that a *component is a directive too*. Remember that a *component is a directive too*.
We can add as many component property bindings as we need by stringing them along in the template We can add as many component property bindings as we need by stringing them along in the template
@ -308,11 +309,10 @@ figure.image-display
<my-component [a]="'a'" [b]="'b'" [c]="'c'"><my-component> <my-component [a]="'a'" [b]="'b'" [c]="'c'"><my-component>
``` ```
We do the same thing with an attribute directive. We do the same thing with an attribute directive.
+makeExample('attribute-directives/ts/src/app/app.component.html', 'defaultColor') +makeExample('attribute-directives/ts/app/app.component.html', 'defaultColor')
:marked :marked
Here we're binding the user's color choice to the `my-highlight` attribute as we did before. Here we're binding the user's color choice to the `myHighlight` attribute as we did before.
We're *also* binding the literal string, 'violet', to the `defaultColor` We're *also* binding the literal string, 'violet', to the `defaultColor`.
(remembering to spell that property in "kebab-case" as *default-color*).
Here is the final version of the directive in action. Here is the final version of the directive in action.
figure.image-display figure.image-display
@ -330,11 +330,11 @@ figure.image-display
The final source: The final source:
+makeTabs( +makeTabs(
`attribute-directives/ts/src/app/app.component.ts, `attribute-directives/ts/app/app.component.ts,
attribute-directives/ts/src/app/app.component.html, attribute-directives/ts/app/app.component.html,
attribute-directives/ts/src/app/highlight.directive.ts, attribute-directives/ts/app/highlight.directive.ts,
attribute-directives/ts/src/app/boot.ts, attribute-directives/ts/app/boot.ts,
attribute-directives/ts/src/index.html attribute-directives/ts/index.html
`, `,
',,full', ',,full',
`app.component.ts, `app.component.ts,