example(template-syntax): follow style-guide and other updates (#2750)
This commit is contained in:
		
							parent
							
								
									7619cdf4a4
								
							
						
					
					
						commit
						64a8754386
					
				| @ -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')); | ||||
|   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()); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
|     input.getAttribute('value').then(size => { | ||||
|       buttons.get(1).click(); | ||||
|       browser.waitForAngular(); | ||||
|       expect(input.getAttribute('value')).toEqual((+size + 1).toString()); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -305,10 +305,10 @@ button</button> | ||||
| 
 | ||||
| <div> | ||||
| <!-- #docregion event-binding-3 --> | ||||
| <!-- `myClick` is an event on the custom `MyClickDirective` --> | ||||
| <!-- #docregion my-click --> | ||||
| <!-- `myClick` is an event on the custom `ClickDirective` --> | ||||
| <!-- #docregion myClick --> | ||||
| <div (myClick)="clickMessage=$event">click with myClick</div> | ||||
| <!-- #enddocregion my-click --> | ||||
| <!-- #enddocregion myClick --> | ||||
| <!-- #enddocregion event-binding-3 --> | ||||
| {{clickMessage}} | ||||
| </div> | ||||
| @ -351,21 +351,22 @@ button</button> | ||||
| <hr><h2 id="two-way">Two-way Binding</h2> | ||||
| <div id="two-way-1"> | ||||
|   <!-- #docregion two-way-1 --> | ||||
|   <my-sizer [(size)]="fontSize"></my-sizer> | ||||
|   <div [style.font-size.px]="fontSize">Resizable Text</div> | ||||
|   <my-sizer [(size)]="fontSizePx"></my-sizer> | ||||
|   <div [style.font-size.px]="fontSizePx">Resizable Text</div> | ||||
|   <!-- #enddocregion two-way-1 --> | ||||
|   <label>FontSize: <input id="fontsize" [(ngModel)]="fontSize"></label> | ||||
|   <label>FontSize (px): <input [(ngModel)]="fontSizePx"></label> | ||||
| </div> | ||||
| <br> | ||||
| <div id="two-way-2"> | ||||
|   <h3>De-sugared two-way binding</h3> | ||||
|   <!-- #docregion two-way-2 --> | ||||
|   <my-sizer [size]="fontSize" (sizeChange)="fontSize=$event"></my-sizer> | ||||
|   <my-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></my-sizer> | ||||
|   <!-- #enddocregion two-way-2 --> | ||||
| </div> | ||||
| <br><br> | ||||
| 
 | ||||
| <a class="to-toc" href="#toc">top</a> | ||||
| 
 | ||||
| <!-- Two way data binding unwound; | ||||
|     passing the changed display value to the event handler via `$event` --> | ||||
| <hr><h2 id="ngModel">NgModel (two-way) Binding</h2> | ||||
| @ -428,6 +429,18 @@ bindon-ngModel | ||||
| <!-- NgStyle binding --> | ||||
| <hr><h2 id="ngStyle">NgStyle Binding</h2> | ||||
| 
 | ||||
| <!-- #docregion NgStyle --> | ||||
| <div> | ||||
|   <p [ngStyle]="setStyle()" #styleP>Change style of this text!</p> | ||||
| 
 | ||||
|   <label>Italic: <input type="checkbox" [(ngModel)]="isItalic"></label> | | ||||
|   <label>Bold: <input type="checkbox" [(ngModel)]="isBold"></label> | | ||||
|   <label>Size: <input type="text" [(ngModel)]="fontSize"></label> | ||||
| 
 | ||||
|   <p>Style set to: <code>'{{styleP.style.cssText}}'</code></p> | ||||
| </div> | ||||
| <!-- #enddocregion NgStyle --> | ||||
| 
 | ||||
| <!-- #docregion NgStyle-1 --> | ||||
| <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" > | ||||
|   This div is x-large. | ||||
|  | ||||
| @ -50,8 +50,6 @@ export class AppComponent implements AfterViewInit, OnInit { | ||||
|     this.alert('Deleted hero: ' + (hero && hero.firstName)); | ||||
|   } | ||||
| 
 | ||||
|   fontSize = 10; | ||||
| 
 | ||||
|   // #docregion evil-title
 | ||||
|   evilTitle = 'Template <script>alert("evil never sleeps")</script>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; | ||||
|  | ||||
| @ -4,7 +4,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 { ClickDirective, ClickDirective2 } from './click.directive'; | ||||
| import { SizerComponent } from './sizer.component'; | ||||
| 
 | ||||
| @NgModule({ | ||||
| @ -16,8 +16,8 @@ import { SizerComponent } from './sizer.component'; | ||||
|     AppComponent, | ||||
|     BigHeroDetailComponent, | ||||
|     HeroDetailComponent, | ||||
|     MyClickDirective, | ||||
|     MyClickDirective2, | ||||
|     ClickDirective, | ||||
|     ClickDirective2, | ||||
|     SizerComponent | ||||
|   ], | ||||
|   bootstrap: [ AppComponent ] | ||||
|  | ||||
| @ -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<string>(); //  @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<string>(); | ||||
|   toggle = false; | ||||
| 
 | ||||
| @ -11,15 +11,14 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; | ||||
|   </div>` | ||||
| }) | ||||
| export class SizerComponent { | ||||
|   @Input()  size: number; | ||||
|   @Input()  size: number | string; | ||||
|   @Output() sizeChange = new EventEmitter<number>(); | ||||
| 
 | ||||
|   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); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| @ -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 | ||||
|   <a id="other-bindings"></a> | ||||
|   ## 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**. | ||||
| @ -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}. | ||||
| @ -683,7 +680,7 @@ block dart-class-binding-bug | ||||
|     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**. | ||||
| 
 | ||||
| @ -747,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 | ||||
| @ -778,7 +775,7 @@ block style-property-name-dart-diff | ||||
| 
 | ||||
|   <a id="eventemitter"></a> | ||||
|   <a id="custom-event"></a> | ||||
|   ### 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. | ||||
| @ -853,36 +850,44 @@ 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 | ||||
|   :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. | ||||
|   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/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 `SizerComponent`: | ||||
| 
 | ||||
| +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>live example</live-example>. | ||||
|   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 <live-example></live-example>. | ||||
| 
 | ||||
|   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=".") | ||||
| 
 | ||||
| +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. | ||||
|   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. | ||||
| 
 | ||||
| @ -1418,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 `<div>` 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. | ||||
| @ -1431,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=".") | ||||
| 
 | ||||
| <a id="expression-operators"></a> | ||||
| .l-main-section | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user