docs: rewrite property binding section and add example (#25770)
PR Close #25770
This commit is contained in:

committed by
Andrew Kushnir

parent
4ad323a4d6
commit
85d38ae564
@ -0,0 +1,9 @@
|
||||
div {
|
||||
margin: 1rem auto;
|
||||
width: 90%
|
||||
}
|
||||
.special {
|
||||
background-color: #1976d2;
|
||||
color: #fff;
|
||||
padding: 1rem;
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
|
||||
|
||||
<div>
|
||||
<h1>Property Binding with Angular</h1>
|
||||
<h2>Binding the src property of an image:</h2>
|
||||
<!-- #docregion property-binding -->
|
||||
<img [src]="itemImageUrl">
|
||||
<!-- #enddocregion property-binding -->
|
||||
<h2>Using bind- syntax:</h2>
|
||||
<!-- #docregion bind-prefix -->
|
||||
<img bind-src="itemImageUrl">
|
||||
<!-- #enddocregion bind-prefix -->
|
||||
<hr />
|
||||
|
||||
<h2>Binding to the colSpan property</h2>
|
||||
<table border=1>
|
||||
<tr><td>Column 1</td><td>Column 2</td></tr>
|
||||
<!-- #docregion colSpan -->
|
||||
<!-- Notice the colSpan property is camel case -->
|
||||
<tr><td [colSpan]="2">Span 2 columns</td></tr>
|
||||
<!-- #enddocregion colSpan -->
|
||||
</table>
|
||||
|
||||
|
||||
<hr />
|
||||
<h2>Button disabled state bound to isUnchanged property:</h2>
|
||||
<!-- #docregion disabled-button -->
|
||||
<!-- Bind button disabled state to `isUnchanged` property -->
|
||||
<button [disabled]="isUnchanged">Disabled Button</button>
|
||||
<!-- #enddocregion disabled-button -->
|
||||
<hr />
|
||||
|
||||
<h2>Binding to a property of a directive</h2>
|
||||
<!-- #docregion class-binding -->
|
||||
<p [ngClass]="classes">[ngClass] binding to the classes property making this blue</p>
|
||||
<!-- #enddocregion class-binding -->
|
||||
<hr />
|
||||
|
||||
<h2>Model property of a custom component:</h2>
|
||||
<!-- #docregion model-property-binding -->
|
||||
<app-item-detail [childItem]="parentItem"></app-item-detail>
|
||||
<!-- #enddocregion model-property-binding -->
|
||||
<!-- #docregion no-evaluation -->
|
||||
<app-item-detail childItem="parentItem"></app-item-detail>
|
||||
<!-- #enddocregion no-evaluation -->
|
||||
|
||||
<h3>Pass objects:</h3>
|
||||
<!-- #docregion pass-object -->
|
||||
<app-list-item [items]="currentItem"></app-list-item>
|
||||
<!-- #enddocregion pass-object -->
|
||||
|
||||
<hr />
|
||||
<h2>Initialized string:</h2>
|
||||
<!-- #docregion string-init -->
|
||||
<app-string-init prefix="This is a one-time initialized string."></app-string-init>
|
||||
<!-- #enddocregion string-init -->
|
||||
|
||||
<hr />
|
||||
|
||||
<h2>Property binding and interpolation</h2>
|
||||
<!-- #docregion property-binding-interpolation -->
|
||||
<p><img src="{{itemImageUrl}}"> is the <i>interpolated</i> image.</p>
|
||||
<p><img [src]="itemImageUrl"> is the <i>property bound</i> image.</p>
|
||||
|
||||
<p><span>"{{interpolationTitle}}" is the <i>interpolated</i> title.</span></p>
|
||||
<p>"<span [innerHTML]="propertyTitle"></span>" is the <i>property bound</i> title.</p>
|
||||
<!-- #enddocregion property-binding-interpolation -->
|
||||
|
||||
<hr />
|
||||
|
||||
<h2>Malicious content</h2>
|
||||
|
||||
<!-- #docregion malicious-interpolated -->
|
||||
<p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p>
|
||||
<!-- #enddocregion malicious-interpolated -->
|
||||
|
||||
<!-- #docregion malicious-content -->
|
||||
<!--
|
||||
Angular generates a warning for the following line as it sanitizes them
|
||||
WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).
|
||||
-->
|
||||
<p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>
|
||||
<!-- #enddocregion malicious-content -->
|
||||
</div>
|
@ -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!');
|
||||
}));
|
||||
});
|
@ -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 <script>alert("evil never sleeps")</script> Syntax';
|
||||
// #enddocregion malicious-content
|
||||
}
|
24
aio/content/examples/property-binding/src/app/app.module.ts
Normal file
24
aio/content/examples/property-binding/src/app/app.module.ts
Normal file
@ -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 { }
|
@ -0,0 +1,4 @@
|
||||
<p>Your item is: {{ childItem }} </p>
|
||||
|
||||
|
||||
|
@ -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<ItemDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ItemDetailComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ItemDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
7
aio/content/examples/property-binding/src/app/item.ts
Normal file
7
aio/content/examples/property-binding/src/app/item.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// #docregion item-class
|
||||
export class Item {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
// #enddocregion item-class
|
||||
|
@ -0,0 +1,11 @@
|
||||
|
||||
<h4>Nested component's list of items:</h4>
|
||||
<ul>
|
||||
<li *ngFor="let item of listItems">{{item.id}} {{item.name}}</li>
|
||||
</ul>
|
||||
|
||||
<h4>Pass an object from parent to nested component:</h4>
|
||||
<ul>
|
||||
<li *ngFor="let item of items">{{item.id}} {{item.name}}</li>
|
||||
</ul>
|
||||
|
@ -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<ListItemComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ListItemComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ListItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -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() { }
|
||||
|
||||
}
|
14
aio/content/examples/property-binding/src/app/mock-items.ts
Normal file
14
aio/content/examples/property-binding/src/app/mock-items.ts
Normal file
@ -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' }
|
||||
];
|
@ -0,0 +1 @@
|
||||
<p>{{prefix}}</p>
|
@ -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<StringInitComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ StringInitComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StringInitComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
BIN
aio/content/examples/property-binding/src/assets/phone.png
Normal file
BIN
aio/content/examples/property-binding/src/assets/phone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
14
aio/content/examples/property-binding/src/index.html
Normal file
14
aio/content/examples/property-binding/src/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>PropertyBinding</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></app-root>
|
||||
</body>
|
||||
</html>
|
12
aio/content/examples/property-binding/src/main.ts
Normal file
12
aio/content/examples/property-binding/src/main.ts
Normal file
@ -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));
|
Reference in New Issue
Block a user