docs(core): in template syntax guide, make SVG example more clear (#31356)

add e2e test for SVG template example
fix template syntax example app
- linting errors
- runtime exceptions
- template type errors
- deprecated type casting
- deprecated currency pipe example

Relates to #30559

PR Close #31356
This commit is contained in:
Michael Prentice 2019-06-30 02:34:15 -04:00 committed by Alex Rickabaugh
parent 95a9d67599
commit 09970d52e8
9 changed files with 67 additions and 45 deletions

View File

@ -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);
});
});

View File

@ -38,6 +38,7 @@
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br>
<a href="#enums">Enums</a><br>
<a href="#svg-templates">SVG Templates</a><br>
<!-- Interpolation and expressions -->
<hr><h2 id="interpolation">Interpolation</h2>
@ -442,7 +443,7 @@ button</button>
<!-- #docregion without-NgModel -->
<input [value]="currentHero.name"
(input)="currentHero.name=$event.target.value" >
(input)="updateCurrentHeroName($event)">
<!-- #enddocregion without-NgModel -->
without NgModel
<br>
@ -752,7 +753,7 @@ bindon-ngModel
<div>
<!-- pipe price to USD and display the $ symbol -->
<label>Price: </label>{{product.price | currency:'USD':true}}
<label>Price: </label>{{product.price | currency:'USD':'symbol'}}
</div>
<a class="to-toc" href="#toc">top</a>
@ -857,3 +858,9 @@ The null hero's name is {{nullHero && nullHero.name}}
</p>
<a class="to-toc" href="#toc">top</a>
<hr><h2 id="svg-templates">SVG Templates</h2>
<!-- #docregion svg-templates -->
<app-svg></app-svg>
<!-- #enddocregion svg-templates -->
<a class="to-toc" href="#toc">top</a>

View File

@ -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<ElementRef>;
@ViewChildren('noTrackBy') heroesNoTrackBy: QueryList<ElementRef>;
@ViewChildren('withTrackBy') heroesWithTrackBy: QueryList<ElementRef>;
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 ' + (<HTMLElement>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 ' + (<HTMLElement>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
}

View File

@ -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: [

View File

@ -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';

View File

@ -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;

View File

@ -1,6 +1,6 @@
<svg>
<g>
<rect x="0" y="0" width="100" height="100" [attr.fill]="fill" (click)="changeColor()" />
<rect x="0" y="0" width="100" height="100" [attr.fill]="fillColor" (click)="changeColor()" />
<text x="120" y="50">click the rectangle to change the fill color</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 201 B

View File

@ -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})`;
}
}

View File

@ -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:
<code-example path="template-syntax/src/app/svg.component.svg" header="src/app/svg.component.svg">
</code-example>
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"`).