diff --git a/aio/content/examples/template-syntax/e2e/src/app.e2e-spec.ts b/aio/content/examples/template-syntax/e2e/src/app.e2e-spec.ts index 71f1c58165..6483774f10 100644 --- a/aio/content/examples/template-syntax/e2e/src/app.e2e-spec.ts +++ b/aio/content/examples/template-syntax/e2e/src/app.e2e-spec.ts @@ -2,42 +2,49 @@ import { browser, element, by } from 'protractor'; -// Not yet complete -describe('Template Syntax', function () { +// TODO Not yet complete +describe('Template Syntax', () => { - beforeAll(function () { + beforeAll(() => { browser.get(''); }); - it('should be able to use interpolation with a hero', function () { - let heroInterEle = element.all(by.css('h2+p')).get(0); + it('should be able to use interpolation with a hero', () => { + const heroInterEle = element.all(by.css('h2+p')).get(0); expect(heroInterEle.getText()).toEqual('My current hero is Hercules'); }); - it('should be able to use interpolation with a calculation', function () { - let theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of')); + it('should be able to use interpolation with a calculation', () => { + const theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of')); expect(theSumEles.count()).toBe(2); expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2'); expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4'); }); - it('should be able to use class binding syntax', function () { - let specialEle = element(by.cssContainingText('div', 'Special')); + it('should be able to use class binding syntax', () => { + const specialEle = element(by.cssContainingText('div', 'Special')); expect(specialEle.getAttribute('class')).toMatch('special'); }); - it('should be able to use style binding syntax', function () { - let specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); + it('should be able to use style binding syntax', () => { + const specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); }); 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'); + const div = element(by.css('div#two-way-1')); + const incButton = div.element(by.buttonText('+')); + const input = div.element(by.css('input')); + const initSize = await input.getAttribute('value'); incButton.click(); expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); }); -}); + it('should change SVG rectangle\'s fill color on click', async () => { + const div = element(by.css('app-svg')); + const colorSquare = div.element(by.css('rect')); + const initialColor = await colorSquare.getAttribute('fill'); + colorSquare.click(); + expect(colorSquare.getAttribute('fill')).not.toEqual(initialColor); + }); +}); diff --git a/aio/content/examples/template-syntax/src/app/app.component.html b/aio/content/examples/template-syntax/src/app/app.component.html index fc5b36d35a..ca61c00896 100644 --- a/aio/content/examples/template-syntax/src/app/app.component.html +++ b/aio/content/examples/template-syntax/src/app/app.component.html @@ -38,6 +38,7 @@ Safe navigation operator ?.
Non-null assertion operator !.
Enums
+SVG Templates

Interpolation

@@ -442,7 +443,7 @@ button + (input)="updateCurrentHeroName($event)"> without NgModel
@@ -752,7 +753,7 @@ bindon-ngModel
- {{product.price | currency:'USD':true}} + {{product.price | currency:'USD':'symbol'}}
top @@ -857,3 +858,9 @@ The null hero's name is {{nullHero && nullHero.name}}

top + +

SVG Templates

+ + + +top diff --git a/aio/content/examples/template-syntax/src/app/app.component.ts b/aio/content/examples/template-syntax/src/app/app.component.ts index 0758ba6516..d39e240895 100644 --- a/aio/content/examples/template-syntax/src/app/app.component.ts +++ b/aio/content/examples/template-syntax/src/app/app.component.ts @@ -5,7 +5,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren } import { Hero } from './hero'; -export enum Color {Red, Green, Blue}; +export enum Color {Red, Green, Blue} /** * Giant grab bag of stuff to drive the chapter @@ -29,7 +29,7 @@ export class AppComponent implements AfterViewInit, OnInit { trackChanges(this.heroesWithTrackBy, () => this.heroesWithTrackByCount++); } - @ViewChildren('noTrackBy') heroesNoTrackBy: QueryList; + @ViewChildren('noTrackBy') heroesNoTrackBy: QueryList; @ViewChildren('withTrackBy') heroesWithTrackBy: QueryList; actionName = 'Go for it'; @@ -66,6 +66,10 @@ export class AppComponent implements AfterViewInit, OnInit { currentHero: Hero; + updateCurrentHeroName(event: Event) { + this.currentHero.name = (event.target as any).value; + } + deleteHero(hero?: Hero) { this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); } @@ -105,13 +109,13 @@ export class AppComponent implements AfterViewInit, OnInit { get nullHero(): Hero { return null; } - onClickMe(event?: KeyboardEvent) { - let evtMsg = event ? ' Event target class is ' + (event.target).className : ''; + onClickMe(event?: MouseEvent) { + const evtMsg = event ? ' Event target class is ' + (event.target as HTMLElement).className : ''; this.alert('Click me.' + evtMsg); } - onSave(event?: KeyboardEvent) { - let evtMsg = event ? ' Event target is ' + (event.target).textContent : ''; + onSave(event?: MouseEvent) { + const evtMsg = event ? ' Event target is ' + (event.target as HTMLElement).textContent : ''; this.alert('Saved.' + evtMsg); if (event) { event.stopPropagation(); } } @@ -140,9 +144,9 @@ export class AppComponent implements AfterViewInit, OnInit { setCurrentClasses() { // CSS classes: added/removed per current state of component properties this.currentClasses = { - 'saveable': this.canSave, - 'modified': !this.isUnchanged, - 'special': this.isSpecial + saveable: this.canSave, + modified: !this.isUnchanged, + special: this.isSpecial }; } // #enddocregion setClasses @@ -164,7 +168,7 @@ export class AppComponent implements AfterViewInit, OnInit { // #enddocregion trackByHeroes // #docregion trackById - trackById(index: number, item: any): number { return item['id']; } + trackById(index: number, item: any): number { return item.id; } // #enddocregion trackById } diff --git a/aio/content/examples/template-syntax/src/app/app.module.ts b/aio/content/examples/template-syntax/src/app/app.module.ts index 55e359ccd2..ca7d5dc68a 100644 --- a/aio/content/examples/template-syntax/src/app/app.module.ts +++ b/aio/content/examples/template-syntax/src/app/app.module.ts @@ -1,14 +1,14 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; import { ClickDirective, ClickDirective2 } from './click.directive'; -import { HeroFormComponent } from './hero-form.component'; -import { heroSwitchComponents } from './hero-switch.components'; -import { SizerComponent } from './sizer.component'; -import { SvgComponent } from './svg.component'; +import { HeroFormComponent } from './hero-form.component'; +import { heroSwitchComponents } from './hero-switch.components'; +import { SizerComponent } from './sizer.component'; +import { SvgComponent } from './svg.component'; @NgModule({ imports: [ diff --git a/aio/content/examples/template-syntax/src/app/click.directive.ts b/aio/content/examples/template-syntax/src/app/click.directive.ts index ef9d68f032..e2eeeee105 100644 --- a/aio/content/examples/template-syntax/src/app/click.directive.ts +++ b/aio/content/examples/template-syntax/src/app/click.directive.ts @@ -1,4 +1,4 @@ -/* tslint:disable use-output-property-decorator directive-class-suffix */ +/* tslint:disable directive-selector directive-class-suffix */ // #docplaster import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; diff --git a/aio/content/examples/template-syntax/src/app/hero-form.component.ts b/aio/content/examples/template-syntax/src/app/hero-form.component.ts index 173cc137de..2b1a48666f 100644 --- a/aio/content/examples/template-syntax/src/app/hero-form.component.ts +++ b/aio/content/examples/template-syntax/src/app/hero-form.component.ts @@ -1,5 +1,5 @@ import { Component, Input, ViewChild } from '@angular/core'; -import { NgForm } from '@angular/forms'; +import { NgForm } from '@angular/forms'; import { Hero } from './hero'; @@ -15,10 +15,11 @@ export class HeroFormComponent { @Input() hero: Hero; @ViewChild('heroForm', {static: false}) form: NgForm; + // tslint:disable-next-line:variable-name private _submitMessage = ''; get submitMessage() { - if (!this.form.valid) { + if (this.form && !this.form.valid) { this._submitMessage = ''; } return this._submitMessage; diff --git a/aio/content/examples/template-syntax/src/app/svg.component.svg b/aio/content/examples/template-syntax/src/app/svg.component.svg index 62431475a0..634b66df8c 100644 --- a/aio/content/examples/template-syntax/src/app/svg.component.svg +++ b/aio/content/examples/template-syntax/src/app/svg.component.svg @@ -1,6 +1,6 @@ - + click the rectangle to change the fill color diff --git a/aio/content/examples/template-syntax/src/app/svg.component.ts b/aio/content/examples/template-syntax/src/app/svg.component.ts index d3f80e143a..7be251a8ef 100644 --- a/aio/content/examples/template-syntax/src/app/svg.component.ts +++ b/aio/content/examples/template-syntax/src/app/svg.component.ts @@ -6,12 +6,12 @@ import { Component } from '@angular/core'; styleUrls: ['./svg.component.css'] }) export class SvgComponent { - fill = 'rgb(255, 0, 0)'; + fillColor = 'rgb(255, 0, 0)'; changeColor() { const r = Math.floor(Math.random() * 256); const g = Math.floor(Math.random() * 256); const b = Math.floor(Math.random() * 256); - this.fill = `rgb(${r}, ${g}, ${b})`; + this.fillColor = `rgb(${r}, ${g}, ${b})`; } } diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index bf11a8e97a..2bc7bc2752 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -2276,12 +2276,14 @@ The `$any()` cast function works anywhere in a binding expression where a method ## SVG in templates -It is possible to use SVG as valid templates in Angular. All of the template syntax below is applicable to both SVG and HTML. -Learn more in the SVG [1.1](https://www.w3.org/TR/SVG11/) and [2.0](https://www.w3.org/TR/SVG2/) specifications. +It is possible to use SVG as valid templates in Angular. All of the template syntax below is +applicable to both SVG and HTML. Learn more in the SVG [1.1](https://www.w3.org/TR/SVG11/) and +[2.0](https://www.w3.org/TR/SVG2/) specifications. Why would you use SVG as template, instead of simply adding it as image to your application? -When you use an SVG as the template, you are able to use directives and bindings just like with HTML templates. This means that you will be able to dynamically generate interactive graphics. +When you use an SVG as the template, you are able to use directives and bindings just like with HTML +templates. This means that you will be able to dynamically generate interactive graphics. Refer to the sample code snippet below for a syntax example: @@ -2293,4 +2295,5 @@ Add the below code to your `svg.component.svg` file: -Here you can see the use of a `click()` event binding and the property binding syntax (`[attr.fill]="fill"`). +Here you can see the use of a `click()` event binding and the property binding syntax +(`[attr.fill]="fillColor"`).