From 85d38ae564a2392c691aab058cbccd49e2b48994 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Tue, 28 Aug 2018 12:46:59 -0400 Subject: [PATCH] docs: rewrite property binding section and add example (#25770) PR Close #25770 --- .../property-binding/e2e/src/app.e2e-spec.ts | 54 ++++ .../property-binding/example-config.json | 0 .../src/app/app.component.css | 9 + .../src/app/app.component.html | 84 ++++++ .../src/app/app.component.spec.ts | 27 ++ .../property-binding/src/app/app.component.ts | 30 ++ .../property-binding/src/app/app.module.ts | 24 ++ .../app/item-detail/item-detail.component.css | 0 .../item-detail/item-detail.component.html | 4 + .../item-detail/item-detail.component.spec.ts | 25 ++ .../app/item-detail/item-detail.component.ts | 26 ++ .../examples/property-binding/src/app/item.ts | 7 + .../src/app/list-item/list-item.component.css | 0 .../app/list-item/list-item.component.html | 11 + .../app/list-item/list-item.component.spec.ts | 25 ++ .../src/app/list-item/list-item.component.ts | 17 ++ .../property-binding/src/app/mock-items.ts | 14 + .../app/string-init/string-init.component.css | 0 .../string-init/string-init.component.html | 1 + .../string-init/string-init.component.spec.ts | 25 ++ .../app/string-init/string-init.component.ts | 17 ++ .../property-binding/src/assets/phone.png | Bin 0 -> 28757 bytes .../examples/property-binding/src/index.html | 14 + .../examples/property-binding/src/main.ts | 12 + .../examples/property-binding/stackblitz.json | 10 + aio/content/guide/template-syntax.md | 266 +++++++++++------- 26 files changed, 601 insertions(+), 101 deletions(-) create mode 100644 aio/content/examples/property-binding/e2e/src/app.e2e-spec.ts create mode 100644 aio/content/examples/property-binding/example-config.json create mode 100644 aio/content/examples/property-binding/src/app/app.component.css create mode 100644 aio/content/examples/property-binding/src/app/app.component.html create mode 100644 aio/content/examples/property-binding/src/app/app.component.spec.ts create mode 100644 aio/content/examples/property-binding/src/app/app.component.ts create mode 100644 aio/content/examples/property-binding/src/app/app.module.ts create mode 100644 aio/content/examples/property-binding/src/app/item-detail/item-detail.component.css create mode 100644 aio/content/examples/property-binding/src/app/item-detail/item-detail.component.html create mode 100644 aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts create mode 100644 aio/content/examples/property-binding/src/app/item-detail/item-detail.component.ts create mode 100644 aio/content/examples/property-binding/src/app/item.ts create mode 100644 aio/content/examples/property-binding/src/app/list-item/list-item.component.css create mode 100644 aio/content/examples/property-binding/src/app/list-item/list-item.component.html create mode 100644 aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts create mode 100644 aio/content/examples/property-binding/src/app/list-item/list-item.component.ts create mode 100644 aio/content/examples/property-binding/src/app/mock-items.ts create mode 100644 aio/content/examples/property-binding/src/app/string-init/string-init.component.css create mode 100644 aio/content/examples/property-binding/src/app/string-init/string-init.component.html create mode 100644 aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts create mode 100644 aio/content/examples/property-binding/src/app/string-init/string-init.component.ts create mode 100644 aio/content/examples/property-binding/src/assets/phone.png create mode 100644 aio/content/examples/property-binding/src/index.html create mode 100644 aio/content/examples/property-binding/src/main.ts create mode 100644 aio/content/examples/property-binding/stackblitz.json diff --git a/aio/content/examples/property-binding/e2e/src/app.e2e-spec.ts b/aio/content/examples/property-binding/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000..07b98491c1 --- /dev/null +++ b/aio/content/examples/property-binding/e2e/src/app.e2e-spec.ts @@ -0,0 +1,54 @@ +import { browser, element, by } from 'protractor'; + + +describe('Property binding e2e tests', () => { + + beforeEach(function () { + browser.get(''); + }); + + it('should display Property Binding with Angular', function () { + expect(element(by.css('h1')).getText()).toEqual('Property Binding with Angular'); + }); + + it('should display four phone pictures', function() { + expect(element.all(by.css('img')).isPresent()).toBe(true); + expect(element.all(by.css('img')).count()).toBe(4); + + }); + + it('should display Disabled button', function () { + expect(element.all(by.css('button')).get(0).getText()).toBe(`Disabled Button`); + }); + + it('should display Binding to a property of a directive', function () { + expect(element.all(by.css('h2')).get(4).getText()).toBe(`Binding to a property of a directive`); + }); + + it('should display Your item is: lamp', function () { + expect(element.all(by.css('p')).get(0).getText()).toContain(`blue`); + }); + it('should display Your item is: lamp', function () { + expect(element.all(by.css('p')).get(1).getText()).toContain(`Your item is: lamp`); + }); + + it('should display Your item is: parentItem', function () { + expect(element.all(by.css('p')).get(2).getText()).toBe(`Your item is: parentItem`); + }); + + it('should display a ul', function () { + expect(element.all(by.css('ul')).get(0).getText()).toContain(`tv`); + }); + + it('should display a ul containing phone', function () { + expect(element.all(by.css('ul')).get(1).getText()).toBe(`21 phone`); + }); + + it('should display one-time initialized string', function () { + expect(element.all(by.css('p')).get(3).getText()).toContain(`one-time initialized`); + }); + + it('should display Malicious content', function () { + expect(element.all(by.css('h2')).get(8).getText()).toBe(`Malicious content`); + }); +}); diff --git a/aio/content/examples/property-binding/example-config.json b/aio/content/examples/property-binding/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/property-binding/src/app/app.component.css b/aio/content/examples/property-binding/src/app/app.component.css new file mode 100644 index 0000000000..91bae844fd --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.component.css @@ -0,0 +1,9 @@ +div { + margin: 1rem auto; + width: 90% +} +.special { + background-color: #1976d2; + color: #fff; + padding: 1rem; +} diff --git a/aio/content/examples/property-binding/src/app/app.component.html b/aio/content/examples/property-binding/src/app/app.component.html new file mode 100644 index 0000000000..e6ca6e5b0a --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.component.html @@ -0,0 +1,84 @@ + + +
+

Property Binding with Angular

+

Binding the src property of an image:

+ + + +

Using bind- syntax:

+ + + +
+ +

Binding to the colSpan property

+ + + + + + +
Column 1Column 2
Span 2 columns
+ + +
+

Button disabled state bound to isUnchanged property:

+ + + + +
+ +

Binding to a property of a directive

+ +

[ngClass] binding to the classes property making this blue

+ +
+ +

Model property of a custom component:

+ + + + + + + +

Pass objects:

+ + + + +
+

Initialized string:

+ + + + +
+ +

Property binding and interpolation

+ +

is the interpolated image.

+

is the property bound image.

+ +

"{{interpolationTitle}}" is the interpolated title.

+

"" is the property bound title.

+ + +
+ +

Malicious content

+ + +

"{{evilTitle}}" is the interpolated evil title.

+ + + + +

"" is the property bound evil title.

+ +
diff --git a/aio/content/examples/property-binding/src/app/app.component.spec.ts b/aio/content/examples/property-binding/src/app/app.component.spec.ts new file mode 100644 index 0000000000..bcbdf36b3e --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.component.spec.ts @@ -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!'); + })); +}); diff --git a/aio/content/examples/property-binding/src/app/app.component.ts b/aio/content/examples/property-binding/src/app/app.component.ts new file mode 100644 index 0000000000..c8dd3b5fe4 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; + + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + itemImageUrl = '../assets/phone.png'; + isUnchanged = true; + classes = 'special'; + // #docregion parent-data-type + parentItem = 'lamp'; + // #enddocregion parent-data-type + + // #docregion pass-object + currentItem = [{ + id: 21, + name: 'phone' + }]; + // #enddocregion pass-object + + interpolationTitle = 'Interpolation'; + propertyTitle = 'Property binding'; + + // #docregion malicious-content + evilTitle = 'Template Syntax'; + // #enddocregion malicious-content +} diff --git a/aio/content/examples/property-binding/src/app/app.module.ts b/aio/content/examples/property-binding/src/app/app.module.ts new file mode 100644 index 0000000000..24c86b6bcf --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.module.ts @@ -0,0 +1,24 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + + +import { AppComponent } from './app.component'; +import { ItemDetailComponent } from './item-detail/item-detail.component'; +import { ListItemComponent } from './list-item/list-item.component'; +import { StringInitComponent } from './string-init/string-init.component'; + + +@NgModule({ + declarations: [ + AppComponent, + ItemDetailComponent, + ListItemComponent, + StringInitComponent + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.css b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.html b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.html new file mode 100644 index 0000000000..050f915d47 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.html @@ -0,0 +1,4 @@ +

Your item is: {{ childItem }}

+ + + diff --git a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts new file mode 100644 index 0000000000..7559cb65f6 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemDetailComponent } from './item-detail.component'; + +describe('ItemDetailComponent', () => { + let component: ItemDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ItemDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.ts b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.ts new file mode 100644 index 0000000000..e16be07036 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit, Input } from '@angular/core'; +// import { Item } from '../item'; +// import { ITEMS } from '../mock-items'; + +@Component({ + selector: 'app-item-detail', + templateUrl: './item-detail.component.html', + styleUrls: ['./item-detail.component.css'] +}) +export class ItemDetailComponent implements OnInit { + + // #docregion input-type + @Input() childItem: string; + // #enddocregion input-type + + // items = ITEMS; + + + currentItem = 'bananas in boxes'; + + constructor() { } + + ngOnInit() { + } + +} diff --git a/aio/content/examples/property-binding/src/app/item.ts b/aio/content/examples/property-binding/src/app/item.ts new file mode 100644 index 0000000000..53bcca4514 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/item.ts @@ -0,0 +1,7 @@ +// #docregion item-class +export class Item { + id: number; + name: string; +} +// #enddocregion item-class + diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.css b/aio/content/examples/property-binding/src/app/list-item/list-item.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.html b/aio/content/examples/property-binding/src/app/list-item/list-item.component.html new file mode 100644 index 0000000000..f19e6c605e --- /dev/null +++ b/aio/content/examples/property-binding/src/app/list-item/list-item.component.html @@ -0,0 +1,11 @@ + +

Nested component's list of items:

+ + +

Pass an object from parent to nested component:

+ + diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts b/aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts new file mode 100644 index 0000000000..0568b6c4c2 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ListItemComponent } from './list-item.component'; + +describe('ItemListComponent', () => { + let component: ListItemComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ListItemComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ListItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.ts b/aio/content/examples/property-binding/src/app/list-item/list-item.component.ts new file mode 100644 index 0000000000..48d1992cde --- /dev/null +++ b/aio/content/examples/property-binding/src/app/list-item/list-item.component.ts @@ -0,0 +1,17 @@ +import { Component, Input } from '@angular/core'; +import { ITEMS } from '../mock-items'; +import { Item } from '../item'; + +@Component({ + selector: 'app-list-item', + templateUrl: './list-item.component.html', + styleUrls: ['./list-item.component.css'] +}) +export class ListItemComponent { + listItems = ITEMS; + // #docregion item-input + @Input() items: Item[]; + // #enddocregion item-input + constructor() { } + +} diff --git a/aio/content/examples/property-binding/src/app/mock-items.ts b/aio/content/examples/property-binding/src/app/mock-items.ts new file mode 100644 index 0000000000..43cd74c5c9 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/mock-items.ts @@ -0,0 +1,14 @@ +import { Item } from './item'; + +export const ITEMS: Item[] = [ + { id: 11, name: 'bottle' }, + { id: 12, name: 'boombox' }, + { id: 13, name: 'chair' }, + { id: 14, name: 'fishbowl' }, + { id: 15, name: 'lamp' }, + { id: 16, name: 'tv' }, + { id: 17, name: 'mug' }, + { id: 18, name: 'paintbrush' }, + { id: 19, name: 'plant' }, + { id: 20, name: 'teapot' } +]; diff --git a/aio/content/examples/property-binding/src/app/string-init/string-init.component.css b/aio/content/examples/property-binding/src/app/string-init/string-init.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/property-binding/src/app/string-init/string-init.component.html b/aio/content/examples/property-binding/src/app/string-init/string-init.component.html new file mode 100644 index 0000000000..b3cd69e133 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/string-init/string-init.component.html @@ -0,0 +1 @@ +

{{prefix}}

diff --git a/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts b/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts new file mode 100644 index 0000000000..2c8e97ec82 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StringInitComponent } from './string-init.component'; + +describe('StringInitComponent', () => { + let component: StringInitComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ StringInitComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StringInitComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/property-binding/src/app/string-init/string-init.component.ts b/aio/content/examples/property-binding/src/app/string-init/string-init.component.ts new file mode 100644 index 0000000000..a49bf41093 --- /dev/null +++ b/aio/content/examples/property-binding/src/app/string-init/string-init.component.ts @@ -0,0 +1,17 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'app-string-init', + templateUrl: './string-init.component.html', + styleUrls: ['./string-init.component.css'] +}) +export class StringInitComponent implements OnInit { + + @Input() prefix: string; + + constructor() { } + + ngOnInit() { + } + +} diff --git a/aio/content/examples/property-binding/src/assets/phone.png b/aio/content/examples/property-binding/src/assets/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..6e60e1f1a1568f495b216f3174c8bf6802648e5d GIT binary patch literal 28757 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 VcQzSg&5Zy6002ovPDHLkV1m8=xS;?5 literal 0 HcmV?d00001 diff --git a/aio/content/examples/property-binding/src/index.html b/aio/content/examples/property-binding/src/index.html new file mode 100644 index 0000000000..01fd8c14ff --- /dev/null +++ b/aio/content/examples/property-binding/src/index.html @@ -0,0 +1,14 @@ + + + + + PropertyBinding + + + + + + + + + diff --git a/aio/content/examples/property-binding/src/main.ts b/aio/content/examples/property-binding/src/main.ts new file mode 100644 index 0000000000..91ec6da5f0 --- /dev/null +++ b/aio/content/examples/property-binding/src/main.ts @@ -0,0 +1,12 @@ +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) + .catch(err => console.log(err)); diff --git a/aio/content/examples/property-binding/stackblitz.json b/aio/content/examples/property-binding/stackblitz.json new file mode 100644 index 0000000000..89869613e4 --- /dev/null +++ b/aio/content/examples/property-binding/stackblitz.json @@ -0,0 +1,10 @@ +{ + "description": "Property Binding", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[0,1,2].*" + ], + "file": "src/app/app.component.ts", + "tags": ["property binding"] +} diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index c77b1f0765..f07416384e 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -643,188 +643,252 @@ The following table summarizes: {@a property-binding} -## Property binding ( [property] ) +## Property binding `[property]` -Write a template **property binding** to set a property of a view element. -The binding sets the property to the value of a [template expression](guide/template-syntax#template-expressions). +Use property binding to _set_ properties of target elements or +directive `@Input()` decorators. For an example +demonstrating all of the points in this section, see the +property binding example. -The most common property binding sets an element property to a component property value. An example is -binding the `src` property of an image element to a component's `heroImageUrl` property: +### One-way in - +Property binding flows a value in one direction, +from a component's property into a target element property. + +You can't use property +binding to read or pull values out of target elements. Similarly, you cannot use +property binding to call a method on the target element. +If the element raises events, you can listen to them with an [event binding](guide/template-syntax#event-binding). + +If you must read a target element property or call one of its methods, +see the API reference for [ViewChild](api/core/ViewChild) and +[ContentChild](api/core/ContentChild). + +### Examples + +The most common property binding sets an element property to a component +property value. An example is +binding the `src` property of an image element to a component's `itemImageUrl` property: + + +Here's an example of binding to the `colSpan` property. Notice that it's not `colspan`, +which is the attribute, spelled with a lowercase `s`. + + + + +For more details, see the [MDN HTMLTableCellElment](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) documentation. + + + Another example is disabling a button when the component says that it `isUnchanged`: - + Another is setting a property of a directive: - + -Yet another is setting the model property of a custom component (a great way -for parent and child components to communicate): +Yet another is setting the model property of a custom component—a great way +for parent and child components to communicate: - + -### One-way *in* - -People often describe property binding as *one-way data binding* because it flows a value in one direction, -from a component's data property into a target element property. - -You cannot use property binding to pull values *out* of the target element. -You can't bind to a property of the target element to _read_ it. You can only _set_ it. - -
- -Similarly, you cannot use property binding to *call* a method on the target element. - -If the element raises events, you can listen to them with an [event binding](guide/template-syntax#event-binding). - -If you must read a target element property or call one of its methods, -you'll need a different technique. -See the API reference for -[ViewChild](api/core/ViewChild) and -[ContentChild](api/core/ContentChild). - -
- ### Binding target -An element property between enclosing square brackets identifies the target property. +An element property between enclosing square brackets identifies +the target property. The target property in the following code is the image element's `src` property. - + -Some people prefer the `bind-` prefix alternative, known as the *canonical form*: +There's also the `bind-` prefix alternative: - + -The target name is always the name of a property, even when it appears to be the name of something else. -You see `src` and may think it's the name of an attribute. No. It's the name of an image element property. + +In most cases, the target name is the name of a property, even +when it appears to be the name of an attribute. +So in this case, `src` is the name of the `` element property. Element properties may be the more common targets, but Angular looks first to see if the name is a property of a known directive, as it is in the following example: - + -
- -Technically, Angular is matching the name to a directive [input](guide/template-syntax#inputs-outputs), -one of the property names listed in the directive's `inputs` array or a property decorated with `@Input()`. +Technically, Angular is matching the name to a directive `@Input()`, +one of the property names listed in the directive's `inputs` array +or a property decorated with `@Input()`. Such inputs map to the directive's own properties. -
- If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error. +
+ +Though the target name is usually the name of a property, +there is an automatic attribute-to-property mapping in Angular for +several common attributes. These include `class`/`className`, `innerHtml`/`innerHTML`, and +`tabindex`/`tabIndex`. + +
+ + ### Avoid side effects -As mentioned previously, evaluation of a template expression should have no visible side effects. -The expression language itself does its part to keep you safe. -You can't assign a value to anything in a property binding expression nor use the increment and decrement operators. +Evaluation of a template expression should have no visible side effects. +The expression language itself, or the way you write template expressions, +helps to a certain extent; +you can't assign a value to anything in a property binding expression +nor use the increment and decrement operators. -Of course, the expression might invoke a property or method that has side effects. -Angular has no way of knowing that or stopping you. - -The expression could call something like `getFoo()`. Only you know what `getFoo()` does. -If `getFoo()` changes something and you happen to be binding to that something, you risk an unpleasant experience. -Angular may or may not display the changed value. Angular may detect the change and throw a warning error. -In general, stick to data properties and to methods that return values and do no more. +For example, you could have an expression that invoked a property or method that had +side effects. The expression could call something like `getFoo()` where only you +know what `getFoo()` does. If `getFoo()` changes something +and you happen to be binding to that something, +Angular may or may not display the changed value. Angular may detect the +change and throw a warning error. +As a best practice, stick to properties and to methods that return +values and avoid side effects. ### Return the proper type -The template expression should evaluate to the type of value expected by the target property. -Return a string if the target property expects a string. -Return a number if the target property expects a number. -Return an object if the target property expects an object. +The template expression should evaluate to the type of value +that the target property expects. +Return a string if the target property expects a string, a number if it +expects a number, an object if it expects an object, and so on. -The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding: +In the following example, the `childItem` property of the `ItemDetailComponent` expects a string, which is exactly what you're sending in the property binding: - + +You can confirm this by looking in the `ItemDetailComponent` where the `@Input` type is set to a string: + + + +As you can see here, the `parentItem` in `AppComponent` is a string, which the `ItemDetailComponent` expects: + + + +#### Passing in an object + +The previous simple example showed passing in a string. To pass in an object, +the syntax and thinking are the same. + +In this scenario, `ListItemComponent` is nested within `AppComponent` and the `item` property expects an object. + + + + +The `item` property is declared in the `ListItemComponent` with a type of `Item` and decorated with `@Input()`: + + + + +In this sample app, an `Item` is an object that has two properties; an `id` and a `name`. + + + + +While a list of items exists in another file, `mock-items.ts`, you can +specify a different item in `app.component.ts` so that the new item will render: + + + + +You just have to make sure, in this case, that you're supplying an object because that's the type of `item` and is what the nested component, `ListItemComponent`, expects. + +In this example, `AppComponent` specifies a different `item` object +(`currentItem`) and passes it to the nested `ListItemComponent`. `ListItemComponent` was able to use `currentItem` because it matches what an `Item` object is according to `item.ts`. The `item.ts` file is where +`ListItemComponent` gets its definition of an `item`. + ### Remember the brackets -The brackets tell Angular to evaluate the template expression. +The brackets, `[]`, tell Angular to evaluate the template expression. If you omit the brackets, Angular treats the string as a constant -and *initializes the target property* with that string. -It does *not* evaluate the string! +and *initializes the target property* with that string: -Don't make the following mistake: - - + -{@a one-time-initialization} + +Omitting the brackets will render the string +`parentItem`, not the value of `parentItem`. ### One-time string initialization You *should* omit the brackets when all of the following are true: * The target property accepts a string value. -* The string is a fixed value that you can bake into the template. +* The string is a fixed value that you can put directly into the template. * This initial value never changes. You routinely initialize attributes this way in standard HTML, and it works just as well for directive and component property initialization. -The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string, +The following example initializes the `prefix` property of the `StringInitComponent` to a fixed string, not a template expression. Angular sets it and forgets about it. - + -The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property. +The `[item]` binding, on the other hand, remains a live binding to the component's `currentItem` property. -{@a property-binding-or-interpolation} - -### Property binding or interpolation? +### Property binding vs. interpolation You often have a choice between interpolation and property binding. The following binding pairs do the same thing: - + -_Interpolation_ is a convenient alternative to _property binding_ in many cases. +Interpolation is a convenient alternative to property binding in +many cases. When rendering data values as strings, there is no +technical reason to prefer one form to the other, though readability +tends to favor interpolation. However, *when setting an element +property to a non-string data value, you must use property binding*. -When rendering data values as strings, there is no technical reason to prefer one form to the other. -You lean toward readability, which tends to favor interpolation. -You suggest establishing coding style rules and choosing the form that -both conforms to the rules and feels most natural for the task at hand. +### Content security -When setting an element property to a non-string data value, you must use _property binding_. +Imagine the following malicious content. -#### Content security - -Imagine the following *malicious content*. - - + -Fortunately, Angular data binding is on alert for dangerous HTML. -It [*sanitizes*](guide/security#sanitization-and-security-contexts) the values before displaying them. -It **will not** allow HTML with script tags to leak into the browser, neither with interpolation +In the component template, the content might be used with interpolation: + + + + +Fortunately, Angular data binding is on alert for dangerous HTML. In the above case, +the HTML displays as is, and the Javascript does not execute. Angular **does not** +allow HTML with script tags to leak into the browser, neither with interpolation nor property binding. - +In the following example, however, Angular [sanitizes](guide/security#sanitization-and-security-contexts) +the values before displaying them. + + -Interpolation handles the script tags differently than property binding but both approaches render the -content harmlessly. - - -
- evil title made safe -
+Interpolation handles the ` Syntax" is the interpolated evil title. +"Template alert("evil never sleeps")Syntax" is the property bound evil title. +```
{@a other-bindings} @@ -855,7 +919,7 @@ table span attributes. They are pure attributes. They do not correspond to element properties, and they do not set element properties. There are no property targets to bind to. -This fact becomes painfully obvious when you write something like this. +This fact becomes obvious when you write something like this. <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> @@ -910,7 +974,7 @@ Instead of an element property between brackets, start with the prefix `class`, optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-name]`. The following examples show how to add and remove the application's "special" class -with class bindings. Here's how to set the attribute without binding: +with class bindings. Here's how to set the attribute without binding: