From 602b2ff1f3ae9446a5d6aeb43a6282d74ee31e7e Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 4 Nov 2016 12:21:31 -0700 Subject: [PATCH 1/4] example(template-syntax): follow style-guide and other updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Follow style guide: rename `sizer.component.ts` to `my-sizer.component.ts` (given the selector `my-sizer`); also appropriately rename class. - Rename `AppComponent.fontSize` to `AppComponent.fontSizePx` because it is assigned to `[style.font-size.px]` and so represents a size in px, not a general font-size value (which could be, e.g., “x-large”). - Added small interactive example of `NgStyle`. --- .../_examples/template-syntax/e2e-spec.ts | 17 +++++---- .../template-syntax/ts/app/app.component.html | 21 ++++++++--- .../template-syntax/ts/app/app.component.ts | 17 +++++++-- .../template-syntax/ts/app/app.module.ts | 4 +-- ...zer.component.ts => my-sizer.component.ts} | 7 ++-- .../docs/ts/latest/guide/template-syntax.jade | 35 +++++++++++-------- 6 files changed, 65 insertions(+), 36 deletions(-) rename public/docs/_examples/template-syntax/ts/app/{sizer.component.ts => my-sizer.component.ts} (78%) diff --git a/public/docs/_examples/template-syntax/e2e-spec.ts b/public/docs/_examples/template-syntax/e2e-spec.ts index b8621c4d2d..71f1c58165 100644 --- a/public/docs/_examples/template-syntax/e2e-spec.ts +++ b/public/docs/_examples/template-syntax/e2e-spec.ts @@ -31,14 +31,13 @@ describe('Template Syntax', function () { expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); }); - it('should two-way bind to sizer', function () { - let buttons = element.all(by.css('div#two-way-1 my-sizer button')); - let input = element(by.css('input#fontsize')); - - input.getAttribute('value').then(size => { - buttons.get(1).click(); - browser.waitForAngular(); - expect(input.getAttribute('value')).toEqual((+size + 1).toString()); - }); + it('should two-way bind to sizer', async () => { + let div = element(by.css('div#two-way-1')); + let incButton = div.element(by.buttonText('+')); + let input = div.element(by.css('input')); + let initSize = await input.getAttribute('value'); + incButton.click(); + expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); }); }); + diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.html b/public/docs/_examples/template-syntax/ts/app/app.component.html index d844154f58..79b4f56b7b 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.component.html +++ b/public/docs/_examples/template-syntax/ts/app/app.component.html @@ -351,21 +351,22 @@


Two-way Binding

- -
Resizable Text
+ +
Resizable Text
- +

De-sugared two-way binding

- +


top +

NgModel (two-way) Binding

@@ -428,6 +429,18 @@

Result: {{currentHero.firstName}}


NgStyle Binding

+ +
+

Change style of this text!

+ + | + | + + +

Style set to: '{{styleP.style.cssText}}'

+
+ +
This div is x-large. diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.ts b/public/docs/_examples/template-syntax/ts/app/app.component.ts index 072c634162..77221587a7 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.component.ts +++ b/public/docs/_examples/template-syntax/ts/app/app.component.ts @@ -50,8 +50,6 @@ export class AppComponent implements AfterViewInit, OnInit { this.alert('Deleted hero: ' + (hero && hero.firstName)); } - fontSize = 10; - // #docregion evil-title evilTitle = 'Template Syntax'; // #enddocregion evil-title @@ -180,6 +178,21 @@ export class AppComponent implements AfterViewInit, OnInit { } // #enddocregion setStyles + // #docregion NgStyle + isItalic = false; + isBold = false; + fontSize: string = 'large'; + fontSizePx: number | string = 14; + + setStyle() { + return { + 'font-style': this.isItalic ? 'italic' : 'normal', + 'font-weight': this.isBold ? 'bold' : 'normal', + 'font-size': this.fontSize + }; + } + // #enddocregion NgStyle + toeChoice = ''; toeChooser(picker: HTMLFieldSetElement) { let choices = picker.children; diff --git a/public/docs/_examples/template-syntax/ts/app/app.module.ts b/public/docs/_examples/template-syntax/ts/app/app.module.ts index db940fad08..974ed2f7e6 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.module.ts +++ b/public/docs/_examples/template-syntax/ts/app/app.module.ts @@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; import { MyClickDirective, MyClickDirective2 } from './my-click.directive'; -import { SizerComponent } from './sizer.component'; +import { MySizerComponent } from './my-sizer.component'; @NgModule({ imports: [ @@ -18,7 +18,7 @@ import { SizerComponent } from './sizer.component'; HeroDetailComponent, MyClickDirective, MyClickDirective2, - SizerComponent + MySizerComponent ], bootstrap: [ AppComponent ] }) diff --git a/public/docs/_examples/template-syntax/ts/app/sizer.component.ts b/public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts similarity index 78% rename from public/docs/_examples/template-syntax/ts/app/sizer.component.ts rename to public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts index cf0ef4af47..ef87b5259e 100644 --- a/public/docs/_examples/template-syntax/ts/app/sizer.component.ts +++ b/public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts @@ -10,16 +10,15 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
` }) -export class SizerComponent { - @Input() size: number; +export class MySizerComponent { + @Input() size: number | string; @Output() sizeChange = new EventEmitter(); dec() { this.resize(-1); } inc() { this.resize(+1); } resize(delta: number) { - const size = +this.size + delta; - this.size = Math.min(40, Math.max(8, size)); + this.size = Math.min(40, Math.max(8, +this.size + delta)); this.sizeChange.emit(this.size); } } diff --git a/public/docs/ts/latest/guide/template-syntax.jade b/public/docs/ts/latest/guide/template-syntax.jade index 9956bcf654..4dec16ea01 100644 --- a/public/docs/ts/latest/guide/template-syntax.jade +++ b/public/docs/ts/latest/guide/template-syntax.jade @@ -668,9 +668,6 @@ code-example(format="nocode"). We can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding. +makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".") -block dart-class-binding-bug - //- N/A - :marked Finally, we can bind to a specific class name. Angular adds the class when the template expression evaluates to #{_truthy}. @@ -854,35 +851,43 @@ block style-property-name-dart-diff Angular offers a special _two-way data binding_ syntax for this purpose, **`[(x)]`**. The `[(x)]` syntax combines the brackets of _Property Binding_, `[x]`, with the parentheses of _Event Binding_, `(x)`. + .callout.is-important header [( )] = banana in a box :marked Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets. + :marked The `[(x)]` syntax is easy to demonstrate when the element has a settable property called `x` and a corresponding event named `xChange`. - Here's a `SizerComponent` that fits the pattern. + Here's a `MySizerComponent` that fits the pattern. It has a `size` value property and a companion `sizeChange` event: -+makeExample('template-syntax/ts/app/sizer.component.ts', null, 'app/sizer.component.ts') + ++makeExample('app/my-sizer.component.ts') + :marked The initial `size` is an input value from a property binding. Clicking the buttons increases or decreases the `size`, within min/max values constraints, and then raises (_emits_) the `sizeChange` event with the adjusted size. - Here's an example in which the `AppComponent.fontSize` is two-way bound to the `SizerComponent`: -+makeExample('template-syntax/ts/app/app.component.html', 'two-way-1')(format=".") + Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `MySizerComponent`: + ++makeExcerpt('app/app.component.html', 'two-way-1', '') + :marked - The `AppComponent.fontSize` establishes the initial `SizerComponent.size` value. - Clicking the buttons updates the `AppComponent.fontSize` via the two-way binding. - The revised `AppComponent.fontSize` value flows through to the _style_ binding, making the displayed text bigger or smaller. - Try it in the live example. + The `AppComponent.fontSizePx` establishes the initial `MySizerComponent.size` value. + Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. + The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. + Try it in the . The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. - Angular _desugars_ the `SizerComponent` binding into this: -+makeExample('template-syntax/ts/app/app.component.html', 'two-way-2')(format=".") + Angular _desugars_ the `MySizerComponent` binding into this: + ++makeExcerpt('app/app.component.html', 'two-way-2', '') + :marked - The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. - Angular assigns the `$event` value to the `AppComponent.fontSize` when the user clicks the buttons. + The `$event` variable contains the payload of the `MySizerComponent.sizeChange` event. + Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. Clearly the two-way binding syntax is a great convenience compared to separate property and event bindings. From b801b4568484468c0be7a9fc0a492ec25481c022 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 4 Nov 2016 14:00:10 -0700 Subject: [PATCH 2/4] Kathy's post-review edits cc @kwalrath --- public/docs/ts/latest/guide/template-syntax.jade | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/public/docs/ts/latest/guide/template-syntax.jade b/public/docs/ts/latest/guide/template-syntax.jade index 4dec16ea01..44d79b00c0 100644 --- a/public/docs/ts/latest/guide/template-syntax.jade +++ b/public/docs/ts/latest/guide/template-syntax.jade @@ -581,7 +581,7 @@ a(id="one-time-initialization") :marked - #### Content Security + #### Content security Imagine the following *malicious content*. +makeExample('template-syntax/ts/app/app.component.ts', 'evil-title')(format=".") :marked @@ -599,10 +599,10 @@ figure.image-display .l-main-section :marked - ## Attribute, Class, and Style Bindings + ## Attribute, class, and style bindings The template syntax provides specialized one-way bindings for scenarios less well suited to property binding. - ### Attribute Binding + ### Attribute binding We can set the value of an attribute directly with an **attribute binding**. .l-sub-section :marked @@ -652,7 +652,7 @@ code-example(format="nocode"). is to set ARIA attributes, as in this example: +makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".") :marked - ### Class Binding + ### Class binding We can add and remove CSS class names from an element’s `class` attribute with a **class binding**. @@ -680,7 +680,7 @@ code-example(format="nocode"). we generally prefer the [NgClass directive](#ngClass) for managing multiple class names at the same time. :marked - ### Style Binding + ### Style binding We can set inline styles with a **style binding**. @@ -744,7 +744,7 @@ block style-property-name-dart-diff on [aliasing input/output properties](#aliasing-io). :marked - If the name fails to match element event or output property of a known directive, + 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 statements @@ -775,7 +775,7 @@ block style-property-name-dart-diff - ### Custom Events with EventEmitter + ### Custom events with EventEmitter Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html). The directive creates an `EventEmitter` and exposes it as a property. @@ -850,7 +850,7 @@ block style-property-name-dart-diff Angular offers a special _two-way data binding_ syntax for this purpose, **`[(x)]`**. The `[(x)]` syntax combines the brackets - of _Property Binding_, `[x]`, with the parentheses of _Event Binding_, `(x)`. + of _property binding_, `[x]`, with the parentheses of _event binding_, `(x)`. .callout.is-important header [( )] = banana in a box From a934ede9695b20f2004758146bfe29e7746f93fe Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Tue, 8 Nov 2016 08:30:41 -0800 Subject: [PATCH 3/4] Kathy's post-review edits 2 --- public/docs/ts/latest/guide/template-syntax.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/ts/latest/guide/template-syntax.jade b/public/docs/ts/latest/guide/template-syntax.jade index 44d79b00c0..452c09caab 100644 --- a/public/docs/ts/latest/guide/template-syntax.jade +++ b/public/docs/ts/latest/guide/template-syntax.jade @@ -490,8 +490,8 @@ table If we must read a target element property or call one of its methods, we'll need a different technique. See the API reference for - [viewChild](../api/core/index/ViewChild-decorator.html) and - [contentChild](../api/core/index/ContentChild-decorator.html). + [ViewChild](../api/core/index/ViewChild-decorator.html) and + [ContentChild](../api/core/index/ContentChild-decorator.html). :marked ### Binding target From da08ad1b66b13a3cca5f7c079f31c7dd054af9db Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 10 Nov 2016 15:07:32 -0800 Subject: [PATCH 4/4] Ward's post-review updates - Keep `my-` and `my` prefixes on selectors (for components and directives respectively). - Drop `my-` from file names. - Drop `My` as component class prefix. --- .../template-syntax/ts/app/app.component.html | 6 +++--- .../template-syntax/ts/app/app.module.ts | 10 +++++----- ...-click.directive.ts => click.directive.ts} | 16 +++++++-------- ...-sizer.component.ts => sizer.component.ts} | 2 +- .../docs/ts/latest/guide/template-syntax.jade | 20 +++++++++---------- 5 files changed, 27 insertions(+), 27 deletions(-) rename public/docs/_examples/template-syntax/ts/app/{my-click.directive.ts => click.directive.ts} (76%) rename public/docs/_examples/template-syntax/ts/app/{my-sizer.component.ts => sizer.component.ts} (95%) diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.html b/public/docs/_examples/template-syntax/ts/app/app.component.html index 79b4f56b7b..30a80412c7 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.component.html +++ b/public/docs/_examples/template-syntax/ts/app/app.component.html @@ -305,10 +305,10 @@

- - + +
click with myClick
- + {{clickMessage}}
diff --git a/public/docs/_examples/template-syntax/ts/app/app.module.ts b/public/docs/_examples/template-syntax/ts/app/app.module.ts index 974ed2f7e6..712b613daf 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.module.ts +++ b/public/docs/_examples/template-syntax/ts/app/app.module.ts @@ -4,8 +4,8 @@ import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; -import { MyClickDirective, MyClickDirective2 } from './my-click.directive'; -import { MySizerComponent } from './my-sizer.component'; +import { ClickDirective, ClickDirective2 } from './click.directive'; +import { SizerComponent } from './sizer.component'; @NgModule({ imports: [ @@ -16,9 +16,9 @@ import { MySizerComponent } from './my-sizer.component'; AppComponent, BigHeroDetailComponent, HeroDetailComponent, - MyClickDirective, - MyClickDirective2, - MySizerComponent + ClickDirective, + ClickDirective2, + SizerComponent ], bootstrap: [ AppComponent ] }) diff --git a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts b/public/docs/_examples/template-syntax/ts/app/click.directive.ts similarity index 76% rename from public/docs/_examples/template-syntax/ts/app/my-click.directive.ts rename to public/docs/_examples/template-syntax/ts/app/click.directive.ts index 1f552277bf..09757bfeaf 100644 --- a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts +++ b/public/docs/_examples/template-syntax/ts/app/click.directive.ts @@ -3,10 +3,10 @@ import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; @Directive({selector: '[myClick]'}) -export class MyClickDirective { - // #docregion my-click-output-1 +export class ClickDirective { + // #docregion output-myClick @Output('myClick') clicks = new EventEmitter(); // @Output(alias) propertyName = ... - // #enddocregion my-click-output-1 + // #enddocregion output-myClick toggle = false; @@ -19,15 +19,15 @@ export class MyClickDirective { } } -// #docregion my-click-output-2 +// #docregion output-myClick2 @Directive({ -// #enddocregion my-click-output-2 + // #enddocregion output-myClick2 selector: '[myClick2]', -// #docregion my-click-output-2 + // #docregion output-myClick2 outputs: ['clicks:myClick'] // propertyName:alias }) -// #enddocregion my-click-output-2 -export class MyClickDirective2 { +// #enddocregion output-myClick2 +export class ClickDirective2 { clicks = new EventEmitter(); toggle = false; diff --git a/public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts b/public/docs/_examples/template-syntax/ts/app/sizer.component.ts similarity index 95% rename from public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts rename to public/docs/_examples/template-syntax/ts/app/sizer.component.ts index ef87b5259e..b6065c8cd1 100644 --- a/public/docs/_examples/template-syntax/ts/app/my-sizer.component.ts +++ b/public/docs/_examples/template-syntax/ts/app/sizer.component.ts @@ -10,7 +10,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; ` }) -export class MySizerComponent { +export class SizerComponent { @Input() size: number | string; @Output() sizeChange = new EventEmitter(); diff --git a/public/docs/ts/latest/guide/template-syntax.jade b/public/docs/ts/latest/guide/template-syntax.jade index 452c09caab..ef9ab05371 100644 --- a/public/docs/ts/latest/guide/template-syntax.jade +++ b/public/docs/ts/latest/guide/template-syntax.jade @@ -775,7 +775,7 @@ block style-property-name-dart-diff - ### Custom events with EventEmitter + ### Custom events with *EventEmitter* Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html). The directive creates an `EventEmitter` and exposes it as a property. @@ -860,33 +860,33 @@ block style-property-name-dart-diff :marked The `[(x)]` syntax is easy to demonstrate when the element has a settable property called `x` and a corresponding event named `xChange`. - Here's a `MySizerComponent` that fits the pattern. + Here's a `SizerComponent` that fits the pattern. It has a `size` value property and a companion `sizeChange` event: -+makeExample('app/my-sizer.component.ts') ++makeExample('app/sizer.component.ts') :marked The initial `size` is an input value from a property binding. Clicking the buttons increases or decreases the `size`, within min/max values constraints, and then raises (_emits_) the `sizeChange` event with the adjusted size. - Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `MySizerComponent`: + Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: +makeExcerpt('app/app.component.html', 'two-way-1', '') :marked - The `AppComponent.fontSizePx` establishes the initial `MySizerComponent.size` value. + The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. Try it in the . The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. - Angular _desugars_ the `MySizerComponent` binding into this: + Angular _desugars_ the `SizerComponent` binding into this: +makeExcerpt('app/app.component.html', 'two-way-2', '') :marked - The `$event` variable contains the payload of the `MySizerComponent.sizeChange` event. + The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. Clearly the two-way binding syntax is a great convenience compared to separate property and event bindings. @@ -1423,7 +1423,7 @@ h3#aliasing-io Aliasing input/output properties Directive consumers expect to bind to the name of the directive. For example, when we apply a directive with a `myClick` selector to a `
` tag, we expect to bind to an event property that is also called `myClick`. -+makeExample('template-syntax/ts/app/app.component.html', 'my-click')(format=".") ++makeExample('template-syntax/ts/app/app.component.html', 'myClick')(format=".") :marked However, the directive name is often a poor choice for the name of a property within the directive class. The directive name rarely describes what the property does. @@ -1436,14 +1436,14 @@ h3#aliasing-io Aliasing input/output properties We can specify the alias for the property name by passing it into the input/output decorator like this: -+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".") ++makeExample('template-syntax/ts/app/click.directive.ts', 'output-myClick')(format=".") .l-sub-section :marked We can also alias property names in the `inputs` and `outputs` #{_array}s. We write a colon-delimited (`:`) string with the directive property name on the *left* and the public alias on the *right*: - +makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-2')(format=".") + +makeExample('template-syntax/ts/app/click.directive.ts', 'output-myClick2')(format=".") .l-main-section