fix: update angular to beta.17 (#378)

This commit is contained in:
Jeremy Elbourn
2016-04-29 18:33:11 -07:00
parent fea5923454
commit 6e4fe5e417
28 changed files with 270 additions and 267 deletions
+3 -3
View File
@@ -25,13 +25,13 @@
"node": ">= 4.2.1 < 5"
},
"dependencies": {
"angular2": "2.0.0-beta.15",
"angular2": "2.0.0-beta.17",
"es6-promise": "^3.0.2",
"es6-shim": "^0.35.0",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2",
"rxjs": "5.0.0-beta.6",
"systemjs": "0.19.20",
"zone.js": "0.6.10"
"zone.js": "0.6.12"
},
"devDependencies": {
"add-stream": "^1.0.0",
+10 -16
View File
@@ -1,16 +1,10 @@
import {
it,
describe,
expect,
beforeEach,
inject,
TestComponentBuilder
} from 'angular2/testing';
import {it, describe, expect, beforeEach, inject, TestComponentBuilder} from 'angular2/testing';
import {Component} from 'angular2/core';
import {By} from 'angular2/platform/browser';
import {MdButton, MdAnchor} from './button';
export function main() {
describe('MdButton', () => {
let builder: TestComponentBuilder;
@@ -21,7 +15,7 @@ export function main() {
// General button tests
it('should apply class based on color attribute', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('button'));
let aDebugElement = fixture.debugElement.query(By.css('a'));
@@ -40,7 +34,7 @@ export function main() {
});
it('should should not clear previous defined classes', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('button'));
@@ -66,7 +60,7 @@ export function main() {
// Regular button tests
describe('button[md-button]', () => {
it('should handle a click on the button', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('button'));
@@ -77,7 +71,7 @@ export function main() {
});
it('should not increment if disabled', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('button'));
@@ -96,7 +90,7 @@ export function main() {
// Anchor button tests
describe('a[md-button]', () => {
it('should not redirect if disabled', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('a'));
@@ -110,7 +104,7 @@ export function main() {
});
it('should remove tabindex if disabled', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('a'));
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null);
@@ -123,7 +117,7 @@ export function main() {
});
it('should add aria-disabled attribute if disabled', (done: () => void) => {
return builder.createAsync(TestApp).then((fixture) => {
return builder.createAsync(TestApp).then(fixture => {
let testComponent = fixture.debugElement.componentInstance;
let buttonDebugElement = fixture.debugElement.query(By.css('a'));
fixture.detectChanges();
+1 -1
View File
@@ -15,7 +15,7 @@ A demo of the checkbox can be found at https://plnkr.co/edit/P7qce8lN9n2flS6kBhD
```html
<ul>
<li *ngFor="#todo of todos">
<li *ngFor="let todo of todos">
<md-checkbox [checked]="todo.completed"
(change)="todo.completed = $event">
{{todo.name}}
+1 -1
View File
@@ -105,7 +105,7 @@ export class MdCheckbox implements ControlValueAccessor {
@Input() tabindex: number = 0;
/** Event emitted when the checkbox's `checked` value changes. */
@Output() change: EventEmitter<boolean> = new EventEmitter();
@Output() change: EventEmitter<boolean> = new EventEmitter<boolean>();
/** Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. */
onTouched: () => any = () => {};
+16 -7
View File
@@ -143,11 +143,11 @@ export class MdIconRegistry {
*/
getSvgIconFromUrl(url: string): Observable<SVGElement> {
if (this._cachedIconsByUrl.has(url)) {
return Observable.of(this._cachedIconsByUrl.get(url).cloneNode(true));
return Observable.of(cloneSvg(this._cachedIconsByUrl.get(url)));
}
return this._loadSvgIconFromConfig(new SvgIconConfig(url))
.do(svg => this._cachedIconsByUrl.set(url, svg))
.map(svg => svg.cloneNode(true));
.map(svg => cloneSvg(svg));
}
/**
@@ -175,12 +175,12 @@ export class MdIconRegistry {
private _getSvgFromConfig(config: SvgIconConfig): Observable<SVGElement> {
if (config.svgElement) {
// We already have the SVG element for this icon, return a copy.
return Observable.of(config.svgElement.cloneNode(true));
return Observable.of(cloneSvg(config.svgElement));
} else {
// Fetch the icon from the config's URL, cache it, and return a copy.
return this._loadSvgIconFromConfig(config)
.do(svg => config.svgElement = svg)
.map(svg => svg.cloneNode(true));
.map(svg => cloneSvg(svg));
}
}
@@ -209,7 +209,7 @@ export class MdIconRegistry {
.filter(iconSetConfig => !iconSetConfig.svgElement)
.map(iconSetConfig =>
this._loadSvgIconSetFromConfig(iconSetConfig)
.catch((err: any, source: any, caught: any): Observable<SVGElement> => {
.catch((err: any, caught: Observable<SVGElement>): Observable<SVGElement> => {
// Swallow errors fetching individual URLs so the combined Observable won't
// necessarily fail.
console.log(`Loading icon set URL: ${iconSetConfig.url} failed: ${err}`);
@@ -349,8 +349,11 @@ export class MdIconRegistry {
if (this._inProgressUrlFetches.has(url)) {
return this._inProgressUrlFetches.get(url);
}
const req = this._http.get(url)
.map((response) => response.text())
// TODO(jelbourn): for some reason, the `finally` operator "loses" the generic type on the
// Observable. Figure out why and fix it.
const req = <Observable<string>> this._http.get(url)
.map(response => response.text())
.finally(() => {
this._inProgressUrlFetches.delete(url);
})
@@ -359,3 +362,9 @@ export class MdIconRegistry {
return req;
}
}
/** Clones an SVGElement while preserving type information. */
function cloneSvg(svg: SVGElement) {
return <SVGElement> svg.cloneNode(true);
}
+27 -28
View File
@@ -1,24 +1,21 @@
import {
it,
describe,
expect,
beforeEach,
beforeEachProviders,
inject,
TestComponentBuilder,
it,
describe,
expect,
beforeEach,
beforeEachProviders,
inject,
TestComponentBuilder
} from 'angular2/testing';
import {
HTTP_PROVIDERS,
XHRBackend} from 'angular2/http';
import {HTTP_PROVIDERS, XHRBackend} from 'angular2/http';
import {MockBackend} from 'angular2/http/testing';
import {
provide,
Component} from 'angular2/core';
import {provide, Component} from 'angular2/core';
import {MdIcon} from './icon';
import {MdIconRegistry} from './icon-registry';
import {getFakeSvgHttpResponse} from './fake-svgs';
/** Returns the CSS classes assigned to an element as a sorted array. */
const sortedClassNames = (elem: Element) => elem.className.split(' ').sort();
@@ -74,7 +71,7 @@ export function main() {
describe('Ligature icons', () => {
it('should add material-icons class by default', (done: () => void) => {
return builder.createAsync(MdIconLigatureTestApp).then((fixture) => {
return builder.createAsync(MdIconLigatureTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.iconName = 'home';
@@ -86,7 +83,7 @@ export function main() {
it('should use alternate icon font if set', (done: () => void) => {
mdIconRegistry.setDefaultFontSetClass('myfont');
return builder.createAsync(MdIconLigatureTestApp).then((fixture) => {
return builder.createAsync(MdIconLigatureTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.iconName = 'home';
@@ -99,7 +96,7 @@ export function main() {
describe('Icons from URLs', () => {
it('should fetch SVG icon from URL and inline the content', (done: () => void) => {
return builder.createAsync(MdIconFromSvgUrlTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -135,7 +132,7 @@ export function main() {
it('should register icon URLs by name', (done: () => void) => {
mdIconRegistry.addSvgIcon('fluffy', 'cat.svg');
mdIconRegistry.addSvgIcon('fido', 'dog.svg');
return builder.createAsync(MdIconFromSvgNameTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: SVGElement;
@@ -168,7 +165,7 @@ export function main() {
it('should extract icon from SVG icon set', (done: () => void) => {
mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg');
return builder.createAsync(MdIconFromSvgNameTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -207,7 +204,7 @@ export function main() {
mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg');
mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-2.svg');
mdIconRegistry.addSvgIconSetInNamespace('arrows', 'arrow-set.svg');
return builder.createAsync(MdIconFromSvgNameTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -250,7 +247,7 @@ export function main() {
it('should not wrap <svg> elements in icon sets in another svg tag', (done: () => void) => {
mdIconRegistry.addSvgIconSet('arrow-set.svg');
return builder.createAsync(MdIconFromSvgNameTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -268,7 +265,7 @@ export function main() {
});
it('should return unmodified copies of icons from URLs', (done: () => void) => {
return builder.createAsync(MdIconFromSvgUrlTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -299,7 +296,7 @@ export function main() {
it('should return unmodified copies of icons from icon sets', (done: () => void) => {
mdIconRegistry.addSvgIconSet('arrow-set.svg');
return builder.createAsync(MdIconFromSvgNameTestApp).then((fixture) => {
return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
let svgElement: any;
@@ -333,7 +330,7 @@ export function main() {
it('should apply CSS classes for custom font and icon', (done: () => void) => {
mdIconRegistry.registerFontClassAlias('f1', 'font1');
mdIconRegistry.registerFontClassAlias('f2');
return builder.createAsync(MdIconCustomFontCssTestApp).then((fixture) => {
return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.fontSet = 'f1';
@@ -361,10 +358,12 @@ export function main() {
describe('aria label', () => {
it('should set aria label from text content if not specified', (done: () => void) => {
return builder.createAsync(MdIconLigatureTestApp).then((fixture) => {
return builder.createAsync(MdIconLigatureTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.iconName = 'home';
fixture.detectChanges();
expect(mdIconElement.getAttribute('aria-label')).toBe('home');
@@ -377,7 +376,7 @@ export function main() {
});
it('should use alt tag if aria label is not specified', (done: () => void) => {
return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then((fixture) => {
return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.iconName = 'home';
@@ -394,7 +393,7 @@ export function main() {
});
it('should use provided aria label rather than icon name', (done: () => void) => {
return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then((fixture) => {
return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.iconName = 'home';
@@ -406,7 +405,7 @@ export function main() {
});
it('should use provided aria label rather than font icon', (done: () => void) => {
return builder.createAsync(MdIconCustomFontCssTestApp).then((fixture) => {
return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => {
const testComponent = fixture.debugElement.componentInstance;
const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon');
testComponent.fontSet = 'f1';
+13 -15
View File
@@ -1,21 +1,20 @@
import {
AfterContentChecked,
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnChanges,
OnInit,
Renderer,
SimpleChange,
ViewEncapsulation,
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnChanges,
OnInit,
Renderer,
SimpleChange,
ViewEncapsulation,
AfterViewChecked
} from 'angular2/core';
import {NgClass} from 'angular2/common';
import {BaseException} from 'angular2/src/facade/exceptions';
import {MdIconRegistry} from './icon-registry';
/** Exception thrown when an invalid icon name is passed to an md-icon component. */
export class MdIconInvalidNameException extends BaseException {
constructor(iconName: string) {
@@ -63,11 +62,10 @@ export class MdIconInvalidNameException extends BaseException {
host: {
'role': 'img',
},
directives: [NgClass],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdIcon implements OnChanges, OnInit, AfterContentChecked {
export class MdIcon implements OnChanges, OnInit, AfterViewChecked {
@Input() svgSrc: string;
@Input() svgIcon: string;
@Input() fontSet: string;
@@ -143,7 +141,7 @@ export class MdIcon implements OnChanges, OnInit, AfterContentChecked {
}
}
ngAfterContentChecked() {
ngAfterViewChecked() {
// Update aria label here because it may depend on the projected text content.
// (e.g. <md-icon>home</md-icon> should use 'home').
this._updateAriaLabel();
+64 -68
View File
@@ -5,18 +5,14 @@ import {
beforeEach,
fakeAsync,
inject,
ComponentFixture,
TestComponentBuilder,
injectAsync,
tick,
} from 'angular2/testing';
import {Component} from 'angular2/core';
import {By} from 'angular2/platform/browser';
import {
MdInput,
MdInputDuplicatedHintException,
MD_INPUT_DIRECTIVES,
MdInputPlaceholderConflictException
} from './input';
@@ -28,17 +24,17 @@ export function main() {
builder = tcb;
}));
it('creates a native <input> element', injectAsync([], () => {
it('creates a native <input> element', () => {
return builder.createAsync(MdInputBaseTestController)
.then((fixture) => {
.then(fixture => {
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('input'))).toBeTruthy();
});
}));
});
it('support ngModel', injectAsync([], () => {
it('support ngModel', () => {
return builder.createAsync(MdInputBaseTestController)
.then((fixture) => {
.then(fixture => {
fixture.detectChanges();
fakeAsync(() => {
let instance = fixture.componentInstance;
@@ -56,25 +52,24 @@ export function main() {
expect(el.value).toEqual('world');
})();
});
}));
});
it('counts characters', injectAsync([], () => {
return builder.createAsync(MdInputBaseTestController)
.then((fixture) => {
let instance = fixture.componentInstance;
fixture.detectChanges();
let inputInstance = fixture.debugElement.query(By.directive(MdInput)).componentInstance;
expect(inputInstance.characterCount).toEqual(0);
it('counts characters', () => {
return builder.createAsync(MdInputBaseTestController).then(fixture => {
let instance = fixture.componentInstance;
fixture.detectChanges();
let inputInstance = fixture.debugElement.query(By.directive(MdInput)).componentInstance;
expect(inputInstance.characterCount).toEqual(0);
instance.model = 'hello';
fixture.detectChanges();
expect(inputInstance.characterCount).toEqual(5);
});
}));
instance.model = 'hello';
fixture.detectChanges();
expect(inputInstance.characterCount).toEqual(5);
});
});
it('copies aria attributes to the inner input', injectAsync([], () => {
it('copies aria attributes to the inner input', () => {
return builder.createAsync(MdInputAriaTestController)
.then((fixture) => {
.then(fixture => {
let instance = fixture.componentInstance;
fixture.detectChanges();
let el: HTMLInputElement = fixture.debugElement.query(By.css('input')).nativeElement;
@@ -85,41 +80,42 @@ export function main() {
expect(el.getAttribute('aria-disabled')).toBeTruthy();
});
}));
});
it('validates there\'s only one hint label per side', () => {
it('validates there\'s only one hint label per side', injectAsync([], () => {
return builder.createAsync(MdInputInvalidHintTestController)
.then((fixture: ComponentFixture) => {
fakeAsync(() => {
.then(fixture => {
expect(() => fixture.detectChanges())
.toThrow(new MdInputDuplicatedHintException('start'));
})();
.toThrow();
// TODO(jelbourn): .toThrow(new MdInputDuplicatedHintException('start'));
// See https://github.com/angular/angular/issues/8348
});
}));
});
it(`validates there's only one hint label per side (attribute)`, injectAsync([], () => {
it(`validates there's only one hint label per side (attribute)`, () => {
return builder.createAsync(MdInputInvalidHint2TestController)
.then((fixture: ComponentFixture) => {
fakeAsync(() => {
expect(() => fixture.detectChanges())
.toThrow(new MdInputDuplicatedHintException('start'));
})();
.then(fixture => {
expect(() => fixture.detectChanges())
.toThrow();
// TODO(jelbourn): .toThrow(new MdInputDuplicatedHintException('start'));
// See https://github.com/angular/angular/issues/8348
});
}));
});
it('validates there\'s only one placeholder', injectAsync([], () => {
it('validates there\'s only one placeholder', () => {
return builder.createAsync(MdInputInvalidPlaceholderTestController)
.then((fixture: ComponentFixture) => {
fakeAsync(() => {
expect(() => fixture.detectChanges())
.toThrow(new MdInputPlaceholderConflictException());
})();
.then(fixture => {
expect(() => fixture.detectChanges())
.toThrow();
// TODO(jelbourn): .toThrow(new MdInputPlaceholderConflictException());
// See https://github.com/angular/angular/issues/8348
});
}));
});
it('validates the type', injectAsync([], () => {
it('validates the type', () => {
return builder.createAsync(MdInputInvalidTypeTestController)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
// Technically this throws during the OnChanges detection phase,
// so the error is really a ChangeDetectionError and it becomes
@@ -129,11 +125,11 @@ export function main() {
.toThrow(/* new MdInputUnsupportedTypeException('file') */);
})();
});
}));
});
it('supports hint labels attribute', injectAsync([], () => {
it('supports hint labels attribute', () => {
return builder.createAsync(MdInputHintLabelTestController)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
fixture.detectChanges();
@@ -145,11 +141,11 @@ export function main() {
expect(fixture.debugElement.query(By.css('.md-hint'))).not.toBeNull();
})();
});
}));
});
it('supports hint labels elements', injectAsync([], () => {
it('supports hint labels elements', () => {
return builder.createAsync(MdInputHintLabel2TestController)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
fixture.detectChanges();
@@ -163,11 +159,11 @@ export function main() {
expect(el.textContent).toBe('label');
})();
});
}));
});
it('supports placeholder attribute', injectAsync([], () => {
it('supports placeholder attribute', () => {
return builder.createAsync(MdInputPlaceholderAttrTestComponent)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
fixture.detectChanges();
@@ -182,11 +178,11 @@ export function main() {
expect(el.nativeElement.textContent).not.toMatch(/\*/g);
})();
});
}));
});
it('supports placeholder element', injectAsync([], () => {
it('supports placeholder element', () => {
return builder.createAsync(MdInputPlaceholderElementTestComponent)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
fixture.detectChanges();
@@ -202,11 +198,11 @@ export function main() {
expect(el.nativeElement.textContent).not.toMatch(/\*/g);
})();
});
}));
});
it('supports placeholder required star', injectAsync([], () => {
it('supports placeholder required star', () => {
return builder.createAsync(MdInputPlaceholderRequiredTestComponent)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fakeAsync(() => {
fixture.detectChanges();
@@ -215,11 +211,11 @@ export function main() {
expect(el.nativeElement.textContent).toMatch(/hello\s+\*/g);
})();
});
}));
});
it('supports number types and conserved its value type from Angular', injectAsync([], () => {
it('supports number types and conserved its value type from Angular', () => {
return builder.createAsync(MdInputNumberTypeConservedTestComponent)
.then((fixture: ComponentFixture) => {
.then(fixture => {
fixture.detectChanges();
const inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
@@ -235,14 +231,14 @@ export function main() {
// Something along the chain of events is asynchronous but does not use Zones, therefore
// we need to wait for that something to propagate. Using fakeAsync fails, just returning
// Promise.resolve(fixture) fails as well, but this passes.
return new Promise((resolve) => {
window.setTimeout(() => resolve(fixture), 0);
return new Promise(resolve => {
setTimeout(() => resolve(fixture), 0);
});
}).then((fixture: any) => {
expect(fixture.componentInstance.value).toBe(3);
expect(typeof fixture.componentInstance.value).toBe('number');
});
}));
});
});
}
+8 -8
View File
@@ -39,7 +39,7 @@ as long as the `md-line` attribute is included.
```html
<!-- two line list -->
<md-list>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<h3 md-line> {{message.from}} </h3>
<p md-line>
<span> {{message.subject}} </span>
@@ -50,7 +50,7 @@ as long as the `md-line` attribute is included.
<!-- three line list -->
<md-list>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<h3 md-line> {{message.from}} </h3>
<p md-line> {{message.subject}} </p>
<p md-line class="demo-2"> {{message.message}} </p>
@@ -72,7 +72,7 @@ To include an avatar, add an image tag with an `md-list-avatar` attribute.
```html
<md-list>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<img md-list-avatar src="..." alt="...">
<h3 md-line> {{message.from}} </h3>
<p md-line>
@@ -113,14 +113,14 @@ use `<md-divider>` tags.
```html
<md-list>
<h3 md-subheader>Folders</h3>
<md-list-item *ngFor="#folder of folders">
<md-list-item *ngFor="let folder of folders">
<md-icon md-list-avatar>folder</md-icon>
<h4 md-line>{{folder.name}}</h4>
<p md-line class="demo-2"> {{folder.updated}} </p>
</md-list-item>
<md-divider></md-divider>
<h3 md-subheader>Notes</h3>
<md-list-item *ngFor="#note of notes">
<md-list-item *ngFor="let note of notes">
<md-icon md-list-avatar>note</md-icon>
<h4 md-line>{{note.name}}</h4>
<p md-line class="demo-2"> {{note.updated}} </p>
@@ -140,7 +140,7 @@ Simple nav lists can tack an `md-list-item` attribute onto the anchor tag itself
```html
<md-nav-list>
<a md-list-item href="..." *ngFor="#link of links"> {{ link }} </a>
<a md-list-item href="..." *ngFor="let link of links"> {{ link }} </a>
</md-nav-list>
```
@@ -148,7 +148,7 @@ If you require a more complex nav list (e.g. with more than one target per item)
```html
<md-nav-list>
<md-list-item *ngFor="#link of links">
<md-list-item *ngFor="let link of links">
<a md-line href="...">{{ link }}</a>
<button md-icon-button (click)="showInfo(link)">
<md-icon>info</md-icon>
@@ -160,4 +160,4 @@ If you require a more complex nav list (e.g. with more than one target per item)
### Lists with secondary text
Secondary text styling will be part of a broader typography module to
[come later](https://github.com/angular/material2/issues/205), and won’t be implemented as part of this component
specifically. Gray text in the examples above comes from a "demo-2" class added manually by the demo.
specifically. Gray text in the examples above comes from a "demo-2" class added manually by the demo.
+5 -5
View File
@@ -39,7 +39,7 @@ export function main() {
it('should apply md-2-line class to lists with two lines', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
<img src="">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
@@ -59,7 +59,7 @@ export function main() {
it('should apply md-3-line class to lists with three lines', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
<p md-line>Some other text</p>
@@ -101,7 +101,7 @@ export function main() {
it('should not clear custom classes provided by user', (done: () => void) => {
var template = `
<md-list>
<md-list-item class="test-class" *ngFor="#item of items">
<md-list-item class="test-class" *ngFor="let item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
</md-list-item>
@@ -119,7 +119,7 @@ export function main() {
it('should update classes if number of lines change', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
<p md-line *ngIf="showThirdLine">Some other text</p>
@@ -145,7 +145,7 @@ export function main() {
it('should add aria roles properly', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
{{item.name}}
</md-list-item>
</md-list>
+2 -2
View File
@@ -15,7 +15,7 @@ A basic radio group would have the following markup.
A dynamic example, populated from a `data` variable:
```html
<md-radio-group [(value)]="groupValue">
<md-radio-button *ngFor="#d of data" [value]="d.value">
<md-radio-button *ngFor="let d of data" [value]="d.value">
{{d.label}}
</md-radio-button>
</md-radio-group>
@@ -24,7 +24,7 @@ A dynamic example, populated from a `data` variable:
A dynamic example for use inside a form showing support for `[(ngModel)]`:
```html
<md-radio-group [(ngModel)]="chosenOption">
<md-radio-button *ngFor="#o of options" [value]="o.value">
<md-radio-button *ngFor="let o of options" [value]="o.value">
{{o.label}}
</md-radio-button>
</md-radio-group>
+33 -27
View File
@@ -29,7 +29,7 @@ export function main() {
<md-radio-button></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
fixture.detectChanges();
@@ -41,7 +41,7 @@ export function main() {
builder
.overrideTemplate(TestApp, '<md-radio-button disabled></md-radio-button>')
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
fixture.detectChanges();
@@ -59,7 +59,7 @@ export function main() {
<md-radio-button></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
fixture.detectChanges();
@@ -74,17 +74,18 @@ export function main() {
<md-radio-button value="1"></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
group.componentInstance.selected = button.componentInstance;
radioGroupInstance.selected = button.componentInstance;
fixture.detectChanges();
expect(group.componentInstance.value).toBe('1');
expect(radioGroupInstance.value).toBe('1');
button.componentInstance.value = '2';
fixture.detectChanges();
expect(group.componentInstance.value).toBe('2');
expect(radioGroupInstance.value).toBe('2');
}).then(done);
});
@@ -92,7 +93,7 @@ export function main() {
builder
.overrideTemplate(TestApp, '<md-radio-button></md-radio-button>')
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
let input = button.query(By.css('input'));
@@ -109,7 +110,7 @@ export function main() {
builder
.overrideTemplate(TestApp, '<md-radio-button></md-radio-button>')
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
fakeAsync(function() {
let button = fixture.debugElement.query(By.css('md-radio-button'));
let changeEvent: MdRadioChange = null;
@@ -130,7 +131,7 @@ export function main() {
builder
.overrideTemplate(TestApp, '<md-radio-button></md-radio-button>')
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let button = fixture.debugElement.query(By.css('md-radio-button'));
let input = button.query(By.css('input'));
@@ -190,17 +191,18 @@ export function main() {
<md-radio-button value="2"></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let buttons = fixture.debugElement.queryAll(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
fixture.detectChanges();
expect(group.componentInstance.selected).toBe(null);
expect(radioGroupInstance.selected).toBe(null);
group.componentInstance.value = '2';
radioGroupInstance.value = '2';
fixture.detectChanges();
expect(group.componentInstance.selected).toBe(buttons[1].componentInstance);
expect(radioGroupInstance.selected).toBe(buttons[1].componentInstance);
}).then(done);
});
@@ -212,18 +214,19 @@ export function main() {
<md-radio-button></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
let buttons = fixture.debugElement.queryAll(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
fixture.detectChanges();
expect(group.componentInstance.selected).toBe(null);
expect(radioGroupInstance.selected).toBe(null);
group.componentInstance.selected = buttons[0].componentInstance;
radioGroupInstance.selected = buttons[0].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[0], buttons)).toBe(true);
group.componentInstance.selected = buttons[1].componentInstance;
radioGroupInstance.selected = buttons[1].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[1], buttons)).toBe(true);
}).then(done);
@@ -237,17 +240,18 @@ export function main() {
<md-radio-button></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
fakeAsync(function() {
let buttons = fixture.debugElement.queryAll(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
let changeEvent: MdRadioChange = null;
group.componentInstance.change.subscribe((evt: MdRadioChange) => {
radioGroupInstance.change.subscribe((evt: MdRadioChange) => {
changeEvent = evt;
});
group.componentInstance.selected = buttons[1].componentInstance;
radioGroupInstance.selected = buttons[1].componentInstance;
fixture.detectChanges();
tick();
@@ -265,22 +269,23 @@ export function main() {
<md-radio-button [value]="1"></md-radio-button>
</md-radio-group>`)
.createAsync(TestApp)
.then((fixture) => {
.then(fixture => {
fakeAsync(function() {
let buttons = fixture.debugElement.queryAll(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
fixture.detectChanges();
expect(buttons[0].componentInstance.checked).toBe(false);
expect(buttons[1].componentInstance.checked).toBe(false);
expect(fixture.componentInstance.choice).toBe(undefined);
group.componentInstance.selected = buttons[0].componentInstance;
radioGroupInstance.selected = buttons[0].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[0], buttons)).toBe(true);
expect(fixture.componentInstance.choice).toBe(0);
group.componentInstance.selected = buttons[1].componentInstance;
radioGroupInstance.selected = buttons[1].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[1], buttons)).toBe(true);
expect(fixture.componentInstance.choice).toBe(1);
@@ -296,21 +301,22 @@ export function main() {
<md-radio-button [value]="1"></md-radio-button>
</md-radio-group>`)
.createAsync(TestAppWithInitialValue)
.then((fixture) => {
.then(fixture => {
fakeAsync(function() {
let buttons = fixture.debugElement.queryAll(By.css('md-radio-button'));
let group = fixture.debugElement.query(By.css('md-radio-group'));
let radioGroupInstance = group.injector.get(MdRadioGroup);
fixture.detectChanges();
expect(isSinglySelected(buttons[1], buttons)).toBe(true);
expect(fixture.componentInstance.choice).toBe(1);
group.componentInstance.selected = buttons[0].componentInstance;
radioGroupInstance.selected = buttons[0].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[0], buttons)).toBe(true);
expect(fixture.componentInstance.choice).toBe(0);
group.componentInstance.selected = buttons[1].componentInstance;
radioGroupInstance.selected = buttons[1].componentInstance;
fixture.detectChanges();
expect(isSinglySelected(buttons[1], buttons)).toBe(true);
expect(fixture.componentInstance.choice).toBe(1);
+2 -2
View File
@@ -77,7 +77,7 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
/** Event emitted when the group value changes. */
@Output()
change: EventEmitter<MdRadioChange> = new EventEmitter();
change: EventEmitter<MdRadioChange> = new EventEmitter<MdRadioChange>();
/** Child radio buttons. */
@ContentChildren(forwardRef(() => MdRadioButton))
@@ -232,7 +232,7 @@ export class MdRadioButton implements OnInit {
/** Event emitted when the group value changes. */
@Output()
change: EventEmitter<MdRadioChange> = new EventEmitter();
change: EventEmitter<MdRadioChange> = new EventEmitter<MdRadioChange>();
constructor(@Optional() radioGroup: MdRadioGroup, public radioDispatcher: MdRadioDispatcher) {
// Assertions. Ideally these should be stripped out by the compiler.
+6 -6
View File
@@ -1,11 +1,11 @@
<div class="md-sidenav-backdrop" (click)="_closeModalSidenav()"
[class.md-sidenav-shown]="_isShowingBackdrop()"></div>
<div class="md-sidenav-backdrop" (click)="closeModalSidenav()"
[class.md-sidenav-shown]="isShowingBackdrop()"></div>
<ng-content select="md-sidenav"></ng-content>
<md-content [style.margin-left.px]="_getMarginLeft()"
[style.margin-right.px]="_getMarginRight()"
[style.left.px]="_getPositionLeft()"
[style.right.px]="_getPositionRight()">
<md-content [style.margin-left.px]="getMarginLeft()"
[style.margin-right.px]="getMarginRight()"
[style.left.px]="getPositionLeft()"
[style.right.px]="getPositionRight()">
<ng-content></ng-content>
</md-content>
+6 -6
View File
@@ -330,7 +330,7 @@ export class MdSidenavLayout implements AfterContentInit {
}
}
private _closeModalSidenav() {
closeModalSidenav() {
if (this._start != null && this._start.mode != 'side') {
this._start.close();
}
@@ -339,7 +339,7 @@ export class MdSidenavLayout implements AfterContentInit {
}
}
private _isShowingBackdrop(): boolean {
isShowingBackdrop(): boolean {
return (this._isSidenavOpen(this._start) && this._start.mode != 'side')
|| (this._isSidenavOpen(this._end) && this._end.mode != 'side');
}
@@ -358,19 +358,19 @@ export class MdSidenavLayout implements AfterContentInit {
return (this._isSidenavOpen(sidenav) && sidenav.mode == mode) ? sidenav._width : 0;
}
private _getMarginLeft() {
getMarginLeft() {
return this._getSidenavEffectiveWidth(this._left, 'side');
}
private _getMarginRight() {
getMarginRight() {
return this._getSidenavEffectiveWidth(this._right, 'side');
}
private _getPositionLeft() {
getPositionLeft() {
return this._getSidenavEffectiveWidth(this._left, 'push');
}
private _getPositionRight() {
getPositionRight() {
return this._getSidenavEffectiveWidth(this._right, 'push');
}
}
+1 -6
View File
@@ -1,6 +1,3 @@
declare var Symbol: any;
/**
* Annotation Factory that allows HTML style boolean attributes. For example,
* a field declared like this:
@@ -17,9 +14,7 @@ declare var Symbol: any;
function booleanFieldValueFactory() {
return function booleanFieldValueMetadata(target: any, key: string): void {
const defaultValue = target[key];
// Use a fallback if Symbol isn't available.
const localKey = Symbol ? Symbol(key) : `__md_private_symbol_${key}`;
const localKey = `__md_private_symbol_${key}`;
target[localKey] = defaultValue;
Object.defineProperty(target, key, {
+5 -6
View File
@@ -10,10 +10,9 @@ import {
beforeEachProviders,
} from 'angular2/testing';
import {
Component,
ViewChild,
ElementRef,
provide,
Component,
ViewChild,
provide, ViewContainerRef,
} from 'angular2/core';
import {TemplatePortalDirective} from '../portal/portal-directives';
import {TemplatePortal, ComponentPortal} from '../portal/portal';
@@ -47,7 +46,7 @@ export function main() {
builder.createAsync(TestComponentWithTemplatePortals).then(fixture => {
fixture.detectChanges();
templatePortal = fixture.componentInstance.templatePortal;
componentPortal = new ComponentPortal(PizzaMsg, fixture.componentInstance.elementRef);
componentPortal = new ComponentPortal(PizzaMsg, fixture.componentInstance.viewContainerRef);
});
flushMicrotasks();
@@ -157,7 +156,7 @@ class PizzaMsg {}
})
class TestComponentWithTemplatePortals {
@ViewChild(TemplatePortalDirective) templatePortal: TemplatePortalDirective;
constructor(public elementRef: ElementRef) { }
constructor(public viewContainerRef: ViewContainerRef) { }
}
class FakePositionStrategy implements PositionStrategy {
+2 -5
View File
@@ -1,6 +1,5 @@
import {
DynamicComponentLoader,
AppViewManager,
OpaqueToken,
Inject,
Injectable,
@@ -40,8 +39,7 @@ let defaultState = new OverlayState();
export class Overlay {
constructor(
@Inject(OVERLAY_CONTAINER_TOKEN) private _overlayContainerElement: HTMLElement,
private _dynamicComponentLoader: DynamicComponentLoader,
private _appViewManager: AppViewManager) {
private _dynamicComponentLoader: DynamicComponentLoader) {
}
/**
@@ -96,8 +94,7 @@ export class Overlay {
private _createPortalHost(pane: HTMLElement): DomPortalHost {
return new DomPortalHost(
pane,
this._dynamicComponentLoader,
this._appViewManager);
this._dynamicComponentLoader);
}
/**
+9 -8
View File
@@ -1,4 +1,4 @@
import {DynamicComponentLoader, AppViewManager, ComponentRef} from 'angular2/core';
import {DynamicComponentLoader, ComponentRef, EmbeddedViewRef} from 'angular2/core';
import {BasePortalHost, ComponentPortal, TemplatePortal} from './portal';
import {MdComponentPortalAttachedToDomWithoutOriginException} from './portal-exceptions';
@@ -12,26 +12,27 @@ import {MdComponentPortalAttachedToDomWithoutOriginException} from './portal-exc
export class DomPortalHost extends BasePortalHost {
constructor(
private _hostDomElement: Element,
private _componentLoader: DynamicComponentLoader,
private _viewManager: AppViewManager) {
private _componentLoader: DynamicComponentLoader) {
super();
}
/** Attach the given ComponentPortal to DOM element using the DynamicComponentLoader. */
attachComponentPortal(portal: ComponentPortal): Promise<ComponentRef> {
if (portal.origin == null) {
if (portal.viewContainerRef == null) {
throw new MdComponentPortalAttachedToDomWithoutOriginException();
}
return this._componentLoader.loadNextToLocation(portal.component, portal.origin).then(ref => {
this._hostDomElement.appendChild(ref.hostView.rootNodes[0]);
this.setDisposeFn(() => ref.dispose());
return this._componentLoader.loadNextToLocation(
portal.component, portal.viewContainerRef).then(ref => {
let hostView = <EmbeddedViewRef> ref.hostView;
this._hostDomElement.appendChild(hostView.rootNodes[0]);
this.setDisposeFn(() => ref.destroy());
return ref;
});
}
attachTemplatePortal(portal: TemplatePortal): Promise<Map<string, any>> {
let viewContainer = this._viewManager.getViewContainer(portal.templateRef.elementRef);
let viewContainer = portal.viewContainerRef;
let viewRef = viewContainer.createEmbeddedView(portal.templateRef);
// TODO(jelbourn): locals don't currently work with DomPortalHost; investigate whether there
// is a bug in Angular.
+9 -7
View File
@@ -3,11 +3,12 @@ import {
Directive,
TemplateRef,
DynamicComponentLoader,
ElementRef,
ViewContainerRef
} from 'angular2/core';
import {Portal, TemplatePortal, ComponentPortal, BasePortalHost} from './portal';
/**
* Directive version of a `TemplatePortal`. Because the directive *is* a TemplatePortal,
* the directive instance itself can be attached to a host, enabling declarative use of portals.
@@ -22,8 +23,8 @@ import {Portal, TemplatePortal, ComponentPortal, BasePortalHost} from './portal'
exportAs: 'portal',
})
export class TemplatePortalDirective extends TemplatePortal {
constructor(templateRef: TemplateRef) {
super(templateRef);
constructor(templateRef: TemplateRef, viewContainerRef: ViewContainerRef) {
super(templateRef, viewContainerRef);
}
}
@@ -45,7 +46,6 @@ export class PortalHostDirective extends BasePortalHost {
constructor(
private _dynamicComponentLoader: DynamicComponentLoader,
private _elementRef: ElementRef,
private _viewContainerRef: ViewContainerRef) {
super();
}
@@ -64,12 +64,14 @@ export class PortalHostDirective extends BasePortalHost {
// If the portal specifies an origin, use that as the logical location of the component
// in the application tree. Otherwise use the location of this PortalHost.
let elementRef = portal.origin != null ? portal.origin : this._elementRef;
let viewContainerRef = portal.viewContainerRef != null ?
portal.viewContainerRef :
this._viewContainerRef;
// Typecast is necessary for Dart transpilation.
return this._dynamicComponentLoader.loadNextToLocation(portal.component, elementRef)
return this._dynamicComponentLoader.loadNextToLocation(portal.component, viewContainerRef)
.then(ref => {
this.setDisposeFn(() => ref.dispose());
this.setDisposeFn(() => ref.destroy());
return ref;
});
}
+13 -16
View File
@@ -7,7 +7,7 @@ import {
ComponentFixture,
TestComponentBuilder,
} from 'angular2/testing';
import {Component, ViewChildren, QueryList, ElementRef} from 'angular2/core';
import {Component, ViewChildren, QueryList, ViewContainerRef} from 'angular2/core';
import {TemplatePortalDirective} from './portal-directives';
import {Portal} from './portal';
import {ComponentPortal} from './portal';
@@ -15,7 +15,6 @@ import {PortalHostDirective} from './portal-directives';
import {fakeAsync} from 'angular2/testing';
import {flushMicrotasks} from 'angular2/testing';
import {DynamicComponentLoader} from 'angular2/core';
import {AppViewManager} from 'angular2/core';
import {DomPortalHost} from './dom-portal-host';
@@ -219,28 +218,26 @@ export function main() {
describe('DomPortalHost', function() {
let componentLoader: DynamicComponentLoader;
let viewManager: AppViewManager;
let someElementRef: ElementRef;
let someViewContainerRef: ViewContainerRef;
let someDomElement: HTMLElement;
let host: DomPortalHost;
beforeEach(inject(
[DynamicComponentLoader, AppViewManager],
fakeAsync((dcl: DynamicComponentLoader, avm: AppViewManager) => {
viewManager = avm;
[DynamicComponentLoader],
fakeAsync((dcl: DynamicComponentLoader) => {
componentLoader = dcl;
someDomElement = document.createElement('div');
host = new DomPortalHost(someDomElement, componentLoader, viewManager);
host = new DomPortalHost(someDomElement, componentLoader);
builder.createAsync(ArbitraryElementRefComponent).then(fixture => {
someElementRef = fixture.componentInstance.elementRef;
builder.createAsync(ArbitraryViewContainerRefComponent).then(fixture => {
someViewContainerRef = fixture.componentInstance.viewContainerRef;
});
flushMicrotasks();
})));
it('should attach and detach a component portal', fakeAsyncTest(() => {
let portal = new ComponentPortal(PizzaMsg, someElementRef);
let portal = new ComponentPortal(PizzaMsg, someViewContainerRef);
let componentInstance: PizzaMsg;
portal.attach(host).then(ref => {
@@ -334,7 +331,7 @@ export function main() {
host.detach();
flushMicrotasks();
host.attach(new ComponentPortal(PizzaMsg, someElementRef));
host.attach(new ComponentPortal(PizzaMsg, someViewContainerRef));
flushMicrotasks();
expect(someDomElement.textContent).toContain('Pizza');
@@ -351,13 +348,13 @@ export function main() {
})
class PizzaMsg {}
/** Simple component to grab an arbitrary ElementRef */
/** Simple component to grab an arbitrary ViewContainerRef */
@Component({
selector: 'some-placeholder',
template: '<p>Hello</p>'
})
class ArbitraryElementRefComponent {
constructor(public elementRef: ElementRef) { }
class ArbitraryViewContainerRefComponent {
constructor(public viewContainerRef: ViewContainerRef) { }
}
@@ -375,7 +372,7 @@ class ArbitraryElementRefComponent {
<template portal> {{fruit}} </template>
<template portal #yum="appetizer">{{yum}}</template>
<template portal let-yum="appetizer">{{yum}}</template>
`,
directives: [PortalHostDirective, TemplatePortalDirective],
})
+9 -5
View File
@@ -1,4 +1,4 @@
import {TemplateRef, Type} from 'angular2/core';
import {TemplateRef, Type, ViewContainerRef} from 'angular2/core';
import {ElementRef} from 'angular2/core';
import {ComponentRef} from 'angular2/core';
@@ -71,12 +71,12 @@ export class ComponentPortal extends Portal<ComponentRef> {
* This is different from where the component *renders*, which is determined by the PortalHost.
* The origin necessary when the host is outside of the Angular application context.
*/
public origin: ElementRef;
public viewContainerRef: ViewContainerRef;
constructor(component: Type, origin: ElementRef = null) {
constructor(component: Type, viewContainerRef: ViewContainerRef = null) {
super();
this.component = component;
this.origin = origin;
this.viewContainerRef = viewContainerRef;
}
}
@@ -88,6 +88,9 @@ export class TemplatePortal extends Portal<Map<string, any>> {
/** The embedded template that will be used to instantiate an embedded View in the host. */
templateRef: TemplateRef;
/** Reference to the ViewContainer into which the template will be stamped out. */
viewContainerRef: ViewContainerRef;
/**
* Additional locals for the instantiated embedded view.
* These locals can be seen as "exports" for the template, such as how ngFor has
@@ -96,9 +99,10 @@ export class TemplatePortal extends Portal<Map<string, any>> {
*/
locals: Map<string, any> = new Map<string, any>();
constructor(template: TemplateRef) {
constructor(template: TemplateRef, viewContainerRef: ViewContainerRef) {
super();
this.templateRef = template;
this.viewContainerRef = viewContainerRef;
}
get origin(): ElementRef {
+2 -2
View File
@@ -1,6 +1,6 @@
<h2>Tasks</h2>
<ul>
<li *ngFor="#task of tasks">
<li *ngFor="let task of tasks">
<md-checkbox [(ngModel)]="task.completed"
[checked]="allComplete(task.subtasks)"
[indeterminate]="someComplete(task.subtasks)"
@@ -8,7 +8,7 @@
<h3>{{task.name}}</h3>
</md-checkbox>
<ul>
<li *ngFor="#subtask of task.subtasks">
<li *ngFor="let subtask of task.subtasks">
<md-checkbox [(ngModel)]="subtask.completed">
{{subtask.name}}
</md-checkbox>
+1 -1
View File
@@ -145,7 +145,7 @@
<button (click)="addABunch(1000)">Add 1000</button>
</td>
</thead>
<tr *ngFor="#item of items; #i = index">
<tr *ngFor="let item of items; let i = index">
<td>{{i+1}}</td>
<td>
<md-input type="number" placeholder="value" aria-label="hello" [(ngModel)]="items[i].value"></md-input>
+12 -12
View File
@@ -9,13 +9,13 @@
<md-list>
<h3 md-subheader>Items</h3>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
{{item}}
</md-list-item>
</md-list>
<md-list>
<md-list-item *ngFor="#contact of contacts">
<md-list-item *ngFor="let contact of contacts">
<h3 md-line>{{contact.name}}</h3>
<p md-line *ngIf="thirdLine">extra line</p>
<p md-line class="demo-secondary-text">{{contact.headline}}</p>
@@ -24,7 +24,7 @@
<md-list>
<h3 md-subheader>Today</h3>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<img md-list-avatar [src]="message.image" alt="Image of {{message.from}}">
<h4 md-line>{{message.from}}</h4>
<p md-line>
@@ -33,7 +33,7 @@
</p>
</md-list-item>
<md-divider></md-divider>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<h4 md-line>{{message.from}}</h4>
<p md-line> {{message.subject}} </p>
<p md-line class="demo-secondary-text">{{message.message}} </p>
@@ -45,13 +45,13 @@
<h2>Dense lists</h2>
<md-list dense>
<h3 md-subheader>Items</h3>
<md-list-item *ngFor="#item of items">
<md-list-item *ngFor="let item of items">
{{item}}
</md-list-item>
</md-list>
<md-list dense>
<md-list-item *ngFor="#contact of contacts">
<md-list-item *ngFor="let contact of contacts">
<h3 md-line>{{contact.name}}</h3>
<p md-line class="demo-secondary-text">{{contact.headline}}</p>
</md-list-item>
@@ -59,7 +59,7 @@
<md-list dense>
<h3 md-subheader>Today</h3>
<md-list-item *ngFor="#message of messages">
<md-list-item *ngFor="let message of messages">
<img md-list-avatar [src]="message.image" alt="Image of {{message.from}}">
<h4 md-line>{{message.from}}</h4>
<p md-line> {{message.subject}} </p>
@@ -70,7 +70,7 @@
<div>
<h2>Nav lists</h2>
<md-nav-list>
<a md-list-item *ngFor="#link of links" href="http://www.google.com">
<a md-list-item *ngFor="let link of links" href="http://www.google.com">
{{ link.name }}
</a>
</md-nav-list>
@@ -78,7 +78,7 @@
More info!
</div>
<md-nav-list>
<md-list-item *ngFor="#link of links">
<md-list-item *ngFor="let link of links">
<a md-line href="http://www.google.com">{{ link.name }}</a>
<button md-icon-button (click)="infoClicked=!infoClicked">
<md-icon>info</md-icon>
@@ -86,14 +86,14 @@
</md-list-item>
</md-nav-list>
<md-nav-list>
<a md-list-item *ngFor="#link of links" href="http://www.google.com">
<a md-list-item *ngFor="let link of links" href="http://www.google.com">
<md-icon md-list-icon>folder</md-icon>
<span md-line>{{ link.name }}</span>
<span md-line class="demo-secondary-text"> Description </span>
</a>
</md-nav-list>
<md-nav-list dense>
<md-list-item *ngFor="#link of links">
<md-list-item *ngFor="let link of links">
<a md-line href="http://www.google.com">{{ link.name }}</a>
<button md-icon-button (click)="infoClicked=!infoClicked">
<md-icon class="material-icons">info</md-icon>
@@ -101,4 +101,4 @@
</md-list-item>
</md-nav-list>
</div>
</div>
</div>
+6 -3
View File
@@ -1,4 +1,7 @@
import {Component, ElementRef, ViewChildren, QueryList, ViewEncapsulation} from 'angular2/core';
import {
Component, ViewChildren, QueryList, ViewEncapsulation,
ViewContainerRef
} from 'angular2/core';
import {
Overlay,
OverlayState} from '../../core/overlay/overlay';
@@ -19,7 +22,7 @@ export class OverlayDemo {
@ViewChildren(TemplatePortalDirective) templatePortals: QueryList<Portal<any>>;
constructor(public overlay: Overlay, public elementRef: ElementRef) { }
constructor(public overlay: Overlay, public viewContainerRef: ViewContainerRef) { }
openRotiniPanel() {
let config = new OverlayState();
@@ -32,7 +35,7 @@ export class OverlayDemo {
this.nextPosition += 30;
this.overlay.create(config).then(ref => {
ref.attach(new ComponentPortal(PastaPanel, this.elementRef));
ref.attach(new ComponentPortal(PastaPanel, this.viewContainerRef));
});
}
+1 -1
View File
@@ -22,7 +22,7 @@
<h2>Dynamic Example with two-way data-binding</h2>
<section class="demo-section">
<md-radio-group name="more_options" [(ngModel)]="favoriteSeason">
<md-radio-button *ngFor="#season of seasonOptions" name="more_options" [value]="season">
<md-radio-button *ngFor="let season of seasonOptions" name="more_options" [value]="season">
{{season}}
</md-radio-button>
</md-radio-group>
+3
View File
@@ -26,6 +26,9 @@ export function config(config) {
// Angular 2 polyfills *must* be loaded after es6-shim and system-polyfills in order to
// setup the monkey-patches for zones.
{pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', included: true, watched: false},
{pattern: 'node_modules/zone.js/dist/jasmine-patch.js', included: true, watched: false},
{pattern: 'node_modules/zone.js/dist/async-test.js', included: true, watched: false},
{pattern: 'node_modules/zone.js/dist/fake-async-test.js', included: true, watched: false},
{pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: false},
{pattern: 'node_modules/rxjs/bundles/Rx.js', included: true, watched: false},
'node_modules/reflect-metadata/Reflect.js',