docs(attribute directives/TS/Dart): remove `Renderer`; improve text

closes #757
This commit is contained in:
Ward Bell 2016-01-26 13:42:17 -08:00
parent 9580248c77
commit 6e11cf6a1e
9 changed files with 52 additions and 70 deletions

View File

@ -32,7 +32,6 @@ class Highlight {
// #enddocregion defaultColor // #enddocregion defaultColor
// #docregion class-1 // #docregion class-1
final Renderer _renderer;
final ElementRef _element; final ElementRef _element;
// #docregion mouse-enter // #docregion mouse-enter
@ -46,10 +45,10 @@ class Highlight {
} }
void _highlight(String color) { void _highlight(String color) {
_renderer.setElementStyle(_element, 'background-color', color); _element.nativeElement.style.backgroundColor = color;
} }
Highlight(this._element, this._renderer); Highlight(this._element);
} }
// #enddocregion class-1 // #enddocregion class-1
// #enddocregion full // #enddocregion full

View File

@ -5,8 +5,7 @@ import 'package:angular2/angular2.dart';
@Directive(selector: '[my-highlight]') @Directive(selector: '[my-highlight]')
class Highlight { class Highlight {
Highlight(ElementRef element, Renderer renderer) { Highlight(ElementRef element) {
//el.nativeElement.style.backgroundColor = 'yellow'; element.nativeElement.style.backgroundColor = 'yellow';
renderer.setElementStyle(element, 'background-color', 'yellow');
} }
} }

View File

@ -12,7 +12,6 @@ import 'package:angular2/angular2.dart';
// #enddocregion host // #enddocregion host
) )
class Highlight { class Highlight {
final Renderer _renderer;
final ElementRef _element; final ElementRef _element;
// #docregion mouse-methods // #docregion mouse-methods
onMouseEnter() { onMouseEnter() {
@ -25,11 +24,11 @@ class Highlight {
// #enddocregion mouse-methods // #enddocregion mouse-methods
void _highlight(String color) { void _highlight(String color) {
_renderer.setElementStyle(_element, 'background-color', color); _element.nativeElement.style.backgroundColor = color;
} }
// #docregion ctor // #docregion ctor
Highlight(this._element, this._renderer); Highlight(this._element);
// #enddocregion ctor // #enddocregion ctor
} }
// #enddocregion // #enddocregion

View File

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

View File

@ -1,5 +1,5 @@
// #docregion // #docregion
import {Directive, ElementRef, Renderer, Input} from 'angular2/core'; import {Directive, ElementRef, Input} from 'angular2/core';
@Directive({ @Directive({
selector: '[myHighlight]', selector: '[myHighlight]',
@ -13,8 +13,7 @@ import {Directive, ElementRef, Renderer, Input} from 'angular2/core';
export class HighlightDirective { export class HighlightDirective {
// #docregion ctor // #docregion ctor
constructor(private el: ElementRef, private renderer: Renderer) { constructor(private el: ElementRef) { }
}
// #enddocregion ctor // #enddocregion ctor
// #docregion mouse-methods // #docregion mouse-methods
@ -22,7 +21,7 @@ export class HighlightDirective {
onMouseLeave() { this._highlight(null); } onMouseLeave() { this._highlight(null); }
private _highlight(color: string) { private _highlight(color: string) {
this.renderer.setElementStyle(this.el, 'backgroundColor', color); this.el.nativeElement.style.backgroundColor = color;
} }
// #enddocregion mouse-methods // #enddocregion mouse-methods

View File

@ -1,6 +1,6 @@
// #docplaster // #docplaster
// #docregion full // #docregion full
import {Directive, ElementRef, Renderer, Input} from 'angular2/core'; import {Directive, ElementRef, Input} from 'angular2/core';
@Directive({ @Directive({
selector: '[myHighlight]', selector: '[myHighlight]',
@ -34,7 +34,7 @@ export class HighlightDirective {
// #enddocregion defaultColor // #enddocregion defaultColor
// #docregion class-1 // #docregion class-1
constructor(private el: ElementRef, private renderer: Renderer) { } constructor(private el: ElementRef) { }
// #docregion mouse-enter // #docregion mouse-enter
onMouseEnter() { this._highlight(this.highlightColor || this._defaultColor); } onMouseEnter() { this._highlight(this.highlightColor || this._defaultColor); }
@ -42,7 +42,7 @@ export class HighlightDirective {
onMouseLeave() { this._highlight(null); } onMouseLeave() { this._highlight(null); }
private _highlight(color:string) { private _highlight(color:string) {
this.renderer.setElementStyle(this.el, 'backgroundColor', color); this.el.nativeElement.style.backgroundColor = color;
} }
} }
// #enddocregion class-1 // #enddocregion class-1

View File

@ -7,21 +7,21 @@
<!-- IE required polyfills, in this exact order --> <!-- IE required polyfills, in this exact order -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script> <script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script> <script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script> <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script> <script src="node_modules/rxjs/bundles/Rx.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: { packages: {
app: { app: {
format: 'register', format: 'register',
defaultExtension: 'js' defaultExtension: 'js'
} }
} }
}); });
System.import('app/boot') System.import('app/main')
.then(null, console.error.bind(console)); .then(null, console.error.bind(console));
</script> </script>
</head> </head>

View File

@ -64,9 +64,9 @@ include ../../../../_includes/_util-fns
:marked :marked
We begin by importing some symbols from the Angular library. We begin by importing some symbols from the Angular library.
We need the `Directive` symbol for the `@Directive` decorator. We need the `Directive` symbol for the `@Directive` decorator.
We need symbols for the *Element Reference* and the *Renderer* service that We need the `ElementRef` to [inject](dependency-injection.html) into the directive's constructor
we will [inject](dependency-injection.html) into the directive's constructor. so we can access the DOM element.
We don't need `Input` now but we will need it later in the chapter. We don't need `Input` immediately but we will need it later in the chapter.
Then we define the directive metadata in a configuration object passed Then we define the directive metadata in a configuration object passed
as an argument to the `@Directive` decorator function. as an argument to the `@Directive` decorator function.
@ -98,40 +98,17 @@ include ../../../../_includes/_util-fns
The directive's controller class contains the logic for the directive. The directive's controller class contains the logic for the directive.
Angular creates a new instance of the directive's controller class for Angular creates a new instance of the directive's controller class for
each matching element, injecting an *Element Reference* and each matching element, injecting an Angular `ElementRef`
the *Renderer* service as arguments to the constructor. into the constructor.
We'll need those *services* to set the element's background color.
Our code shows two ways to set the color.
We could access the `nativeElement` property of the element reference `ElementRef` is a service that grants us direct access to the DOM element
and set the element's background color using the browser DOM API. We don't need through its `nativeElement` property.
the `Renderer` for this approach. That's all we need to set the element's background color using the browser DOM API.
We commented this technique out. It works. But we don't like it.
We prefer the second way that relies on the `Renderer` service
to set the element properties.
.l-sub-section
:marked
### Why prefer the Renderer?
Manipulating the DOM directly is a practice we'd rather *avoid* because it chains us
to the browser DOM API.
The `Renderer` insulates our code from the browser's API.
That gives us options.
The rendering phase could be offloaded to a Web Worker for faster performance.
Our directive might work when we ran the application outside the browser,
perhaps on the server in a pre-render phase.
Server-side rendering can make our application load faster and
is often friendlier to Search Engine Optimizations (SEO).
:marked
.l-main-section .l-main-section
:marked :marked
## Apply the attribute directive ## Apply the attribute directive
The `AppComponent` will be the test harness for our `HighlightDirective`. The `AppComponent` in this sample is a test harness for our `HighlightDirective`.
Let's give it a new template that Let's give it a new template that
applies the directive as an attribute to a `span` element. applies the directive as an attribute to a `span` element.
In Angular terms, the `<span>` element will be the attribute **host**. In Angular terms, the `<span>` element will be the attribute **host**.
@ -147,19 +124,31 @@ include ../../../../_includes/_util-fns
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 `myHighlight` in the template. will recognize our directive when it encounters `myHighlight` in the template.
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.
figure.image-display figure.image-display
img(src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight") img(src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight")
.l-sub-section
:marked
#### Why isn't my directive working?
Did you remember to set the `directives` array? It is easy to forget!
Open the console in the browser tools and look for an error like this:
code-example.format("").
EXCEPTION: Template parse errors:
Can't bind to 'myHighlight' since it isn't a known native property
:marked
Angular detects that we're trying to bind to *something* but it doesn't know what.
We have to tell it by listing `HighlightDirective` in the `directives` metadata array.
:marked :marked
Let's recap what happened. Let's recap what happened.
Angular found the `myHighlight` attribute on the `<span>` element. It created Angular found the `myHighlight` attribute on the `<span>` element. It created
an instance of the `HighlightDirective` class, an instance of the `HighlightDirective` class,
injecting both a reference to the element and the `Renderer` service into the constructor. injecting a reference to the element into the constructor
The constructor told the `Renderer` to set the `<span>` element's background style to yellow. where we set the `<span>` element's background style to yellow.
.l-main-section .l-main-section
:marked :marked
@ -195,12 +184,11 @@ figure.image-display
Now we implement those two mouse event handlers: Now we implement those two mouse event handlers:
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','mouse-methods')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','mouse-methods')(format=".")
:marked :marked
Notice that they delegate to a helper method that calls the `Renderer` service Notice that they delegate to a helper method to set the color.
as we used to do in the constructor.
We no longer need the constructor body but We no longer need the constructor body but
we still want the injected `ElementRef` and `Renderer` service. we still want the injected `ElementRef`.
We revise the constructor signature to capture the injectables in private variables We revise the constructor signature to capture the injected `ElementRef` in a private variable
and clear the body. and clear the body.
+makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')(format=".") +makeExample('attribute-directives/ts/app/highlight.directive.2.ts','ctor')(format=".")
:marked :marked
@ -233,12 +221,11 @@ figure.image-display
: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 `myHighlight` alias. under the `myHighlight` alias.
We must add this input metadata. We must add this input metadata or Angular will reject the binding.
Angular will reject a binding to this property if we don't declare it as an input.
See the [appendix](#why-input) below to learn why. See the [appendix](#why-input) below to learn why.
.l-sub-section .l-sub-section
:marked :marked
### @Input(alias)
The developer who uses our directive expects to bind to the attribute name, `myHighlight`. 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.
@ -333,14 +320,14 @@ figure.image-display
`attribute-directives/ts/app/app.component.ts, `attribute-directives/ts/app/app.component.ts,
attribute-directives/ts/app/app.component.html, attribute-directives/ts/app/app.component.html,
attribute-directives/ts/app/highlight.directive.ts, attribute-directives/ts/app/highlight.directive.ts,
attribute-directives/ts/app/boot.ts, attribute-directives/ts/app/main.ts,
attribute-directives/ts/index.html attribute-directives/ts/index.html
`, `,
',,full', ',,full',
`app.component.ts, `app.component.ts,
app.component.html, app.component.html,
highlight.directive.ts, highlight.directive.ts,
boot.ts, main.ts,
index.html index.html
`) `)
@ -359,9 +346,9 @@ figure.image-display
Angular makes a subtle but important distinction between binding **sources** and **targets**. Angular makes a subtle but important distinction between binding **sources** and **targets**.
In all previous bindings, the directive or component property was a binding ***source***. In all previous bindings, the directive or component property was a binding ***source***.
A property is a *source* if it appears in the template expression to the ***right*** of the (=). A property is a *source* if it appears in the template expression to the ***right*** of the equals (=).
A property is a *target* when it appears to the **left** of the (=) ... A property is a *target* when it appears in **square brackets** ([ ]) to the **left** of the equals (=) ...
as it is does when we bind to the `myHighlight` property of the `HighlightDirective`, as it is does when we bind to the `myHighlight` property of the `HighlightDirective`,
+makeExample('attribute-directives/ts/app/app.component.html','span')(format=".") +makeExample('attribute-directives/ts/app/app.component.html','span')(format=".")
:marked :marked