docs: edit template ref vars copy and example (#27371)

PR Close #27371
This commit is contained in:
Kapunahele Wong 2018-11-29 12:49:29 -05:00 committed by Andrew Kushnir
parent 2c2135d331
commit e2fd628618
11 changed files with 265 additions and 34 deletions

View File

@ -0,0 +1,62 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
import { logging } from 'selenium-webdriver';
describe('Template-reference-variables-example', function() {
beforeEach(function() {
browser.get('');
});
// helper function used to test what's logged to the console
async function logChecker(button, contents) {
const logs = await browser
.manage()
.logs()
.get(logging.Type.BROWSER);
const message = logs.filter(({ message }) =>
message.indexOf(contents) !== -1 ? true : false
);
expect(message.length).toBeGreaterThan(0);
}
it('should display Template reference variables', function() {
expect(element(by.css('h1')).getText()).toEqual(
'Template reference variables'
);
});
it('should log a Calling 123 ... message', async () => {
let callButton = element.all(by.css('button')).get(0);
let phoneInput = element.all(by.css('input')).get(0);
await phoneInput.sendKeys('123');
await callButton.click();
const contents = 'Calling 123 ...';
await logChecker(callButton, contents);
});
it('should log a Faxing 123 ... message', async () => {
let faxButton = element.all(by.css('button')).get(1);
let faxInput = element.all(by.css('input')).get(1);
await faxInput.sendKeys('123');
await faxButton.click();
const contents = 'Faxing 123 ...';
await logChecker(faxButton, contents);
});
it('should display a disabled button', function() {
let disabledButton = element.all(by.css('button')).get(2);
expect(disabledButton.isEnabled()).toBe(false);
});
it('should submit form', async () => {
let submitButton = element.all(by.css('button')).get(3);
let nameInput = element.all(by.css('input')).get(2);
await nameInput.sendKeys('123');
await submitButton.click();
expect(element.all(by.css('div > p')).get(2).getText()).toEqual('Submitted. Form value is {"name":"123"}');
});
});

View File

@ -0,0 +1,55 @@
<h1>Template reference variables</h1>
<div>
<h2>Pass value to an event handler</h2>
<p>See console for output.</p>
<!-- #docregion ref-phone -->
<!-- #docregion ref-var -->
<input #phone placeholder="phone number" />
<!-- #enddocregion ref-var -->
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>
<!-- #enddocregion ref-phone -->
</div>
<div>
<!-- #docregion ref-fax -->
<input ref-fax placeholder="fax number" />
<button (click)="callFax(fax.value)">Fax</button>
<!-- #enddocregion ref-fax -->
</div>
<hr />
<div>
<h2>Template reference variable with disabled button</h2>
<p>btn refers to the button element.</p>
<button
#btn
disabled
[innerHTML]="'disabled by attribute: ' + btn.disabled"
></button>
</div>
<hr />
<h2>Reference variables, forms, and NgForm</h2>
<!-- #docregion ngForm -->
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name"
>Name <input class="form-control" name="name" ngModel required />
</label>
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
<!-- #enddocregion ngForm -->
<p>JSON: {{ itemForm.form.value | json }}</p>

View File

@ -0,0 +1,27 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
}));
});

View File

@ -0,0 +1,31 @@
import { Component, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild('itemForm', { static: false }) form: NgForm;
private _submitMessage = '';
get submitMessage() {
return this._submitMessage;
}
onSubmit(form: NgForm) {
this._submitMessage = 'Submitted. Form value is ' + JSON.stringify(form.value);
}
callPhone(value: string) {
console.warn(`Calling ${value} ...`);
}
callFax(value: string) {
console.warn(`Faxing ${value} ...`);
}
}

View File

@ -0,0 +1,22 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Template Reference Variables Example</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>

View File

@ -0,0 +1,11 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,6 @@
{
"description": "Template Reference Variables",
"files": ["!**/*.d.ts", "!**/*.js", "!**/*.[1,2].*"],
"file": "src/app/app.component.ts",
"tags": ["Template Reference Variables"]
}

View File

@ -1686,70 +1686,73 @@ For example, you could replace the `<app-best-item>` switch case with the follow
{@a template-reference-variable} {@a template-reference-variable}
{@a template-reference-variables--var-}
{@a ref-vars} {@a ref-vars}
{@a ref-var} {@a ref-var}
## Template reference variables ( <span class="syntax">#var</span> ) ## Template reference variables (`#var`)
A **template reference variable** is often a reference to a DOM element within a template. A **template reference variable** is often a reference to a DOM element within a template.
It can also be a reference to an Angular component or directive or a It can also refer to a directive (which contains a component), an element, [TemplateRef](api/core/TemplateRef), or a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" title="MDN: Web Components">web component</a>.
<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" title="MDN: Web Components">web component</a>.
For a demonstration of the syntax and code snippets in this section, see the <live-example name="template-reference-variables">template reference variables example</live-example>.
Use the hash symbol (#) to declare a reference variable. Use the hash symbol (#) to declare a reference variable.
The `#phone` declares a `phone` variable on an `<input>` element. The following reference variable, `#phone`, declares a `phone` variable on an `<input>` element.
<code-example path="template-syntax/src/app/app.component.html" region="ref-var" header="src/app/app.component.html" linenums="false"> <code-example path="template-reference-variables/src/app/app.component.html" region="ref-var" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can refer to a template reference variable _anywhere_ in the template. You can refer to a template reference variable anywhere in the component's template.
The `phone` variable declared on this `<input>` is Here, a `<button>` further down the template refers to the `phone` variable.
consumed in a `<button>` on the other side of the template
<code-example path="template-syntax/src/app/app.component.html" region="ref-phone" header="src/app/app.component.html" linenums="false"> <code-example path="template-reference-variables/src/app/app.component.html" region="ref-phone" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<h3 class="no-toc">How a reference variable gets its value</h3> <h3 class="no-toc">How a reference variable gets its value</h3>
In most cases, Angular sets the reference variable's value to the element on which it was declared. In most cases, Angular sets the reference variable's value to the element on which it is declared.
In the previous example, `phone` refers to the _phone number_ `<input>` box. In the previous example, `phone` refers to the phone number `<input>`.
The phone button click handler passes the _input_ value to the component's `callPhone` method. The button's click handler passes the `<input>` value to the component's `callPhone()` method.
But a directive can change that behavior and set the value to something else, such as itself.
The `NgForm` directive does that.
The following is a *simplified* version of the form example in the [Forms](guide/forms) guide. The `NgForm` directive can change that behavior and set the value to something else. In the following example, the template reference variable, `itemForm`, appears three times separated
by HTML.
<code-example path="template-syntax/src/app/hero-form.component.html" header="src/app/hero-form.component.html" linenums="false"> <code-example path="template-reference-variables/src/app/app.component.html" region="ngForm" header="src/app/hero-form.component.html" linenums="false">
</code-example> </code-example>
A template reference variable, `heroForm`, appears three times in this example, separated The reference value of itemForm, without the ngForm attribute value, would be
by a large amount of HTML. the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement).
What is the value of `heroForm`? There is, however, a difference between a Component and a Directive in that a `Component
`will be referenced without specifying the attribute value, and a `Directive` will not
change the implicit reference (that is, the element).
If Angular hadn't taken it over when you imported the `FormsModule`,
it would be the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement).
The `heroForm` is actually a reference to an Angular [NgForm](api/forms/NgForm "API: NgForm") However, with `NgForm`, `itemForm` is a reference to the [NgForm](api/forms/NgForm "API: NgForm")
directive with the ability to track the value and validity of every control in the form. directive with the ability to track the value and validity of every control in the form.
The native `<form>` element doesn't have a `form` property. The native `<form>` element doesn't have a `form` property, but the `NgForm` directive does, which allows disabling the submit button
But the `NgForm` directive does, which explains how you can disable the submit button if the `itemForm.form.valid` is invalid and passing the entire form control tree
if the `heroForm.form.valid` is invalid and pass the entire form control tree to the parent component's `onSubmit()` method.
to the parent component's `onSubmit` method.
<h3 class="no-toc">Template reference variable warning notes</h3> <h3 class="no-toc">Template reference variable considerations</h3>
A template _reference_ variable (`#phone`) is _not_ the same as a template _input_ variable (`let phone`) A template _reference_ variable (`#phone`) is not the same as a template _input_ variable (`let phone`) such as in an [`*ngFor`](guide/template-syntax#template-input-variable).
such as you might see in an [`*ngFor`](guide/template-syntax#template-input-variable). See [_Structural Directives_](guide/structural-directives#template-input-variable) for more information.
Learn the difference in the [_Structural Directives_](guide/structural-directives#template-input-variable) guide.
The scope of a reference variable is the _entire template_. The scope of a reference variable is the entire template. So, don't define the same variable name more than once in the same template as the runtime value will be unpredictable.
Do not define the same variable name more than once in the same template.
The runtime value will be unpredictable. #### Alternative syntax
You can use the `ref-` prefix alternative to `#`. You can use the `ref-` prefix alternative to `#`.
This example declares the `fax` variable as `ref-fax` instead of `#fax`. This example declares the `fax` variable as `ref-fax` instead of `#fax`.
<code-example path="template-syntax/src/app/app.component.html" region="ref-fax" header="src/app/app.component.html" linenums="false">
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-fax" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>