mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(portal): rename PortalHost to PortalOutlet (#7546)
Renames the `PortalHost` and related symbols to `PortalOutlet` for consistency with core. Fixes #7544.
This commit is contained in:
committed by
mmalerba
parent
f601e8335f
commit
00de3f6509
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {NgZone} from '@angular/core';
|
||||
import {PortalHost, Portal} from '@angular/cdk/portal';
|
||||
import {PortalOutlet, Portal} from '@angular/cdk/portal';
|
||||
import {OverlayConfig} from './overlay-config';
|
||||
import {OverlayKeyboardDispatcher} from './keyboard/overlay-keyboard-dispatcher';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
@@ -19,7 +19,7 @@ import {first} from 'rxjs/operators';
|
||||
* Reference to an overlay that has been created with the Overlay service.
|
||||
* Used to manipulate or dispose of said overlay.
|
||||
*/
|
||||
export class OverlayRef implements PortalHost {
|
||||
export class OverlayRef implements PortalOutlet {
|
||||
private _backdropElement: HTMLElement | null = null;
|
||||
private _backdropClick: Subject<any> = new Subject();
|
||||
private _attachments = new Subject<void>();
|
||||
@@ -29,7 +29,7 @@ export class OverlayRef implements PortalHost {
|
||||
_keydownEvents = new Subject<KeyboardEvent>();
|
||||
|
||||
constructor(
|
||||
private _portalHost: PortalHost,
|
||||
private _portalOutlet: PortalOutlet,
|
||||
private _pane: HTMLElement,
|
||||
private _config: OverlayConfig,
|
||||
private _ngZone: NgZone,
|
||||
@@ -51,7 +51,7 @@ export class OverlayRef implements PortalHost {
|
||||
* @returns The portal attachment result.
|
||||
*/
|
||||
attach(portal: Portal<any>): any {
|
||||
let attachResult = this._portalHost.attach(portal);
|
||||
let attachResult = this._portalOutlet.attach(portal);
|
||||
|
||||
if (this._config.positionStrategy) {
|
||||
this._config.positionStrategy.attach(this);
|
||||
@@ -118,7 +118,7 @@ export class OverlayRef implements PortalHost {
|
||||
this._config.scrollStrategy.disable();
|
||||
}
|
||||
|
||||
const detachmentResult = this._portalHost.detach();
|
||||
const detachmentResult = this._portalOutlet.detach();
|
||||
|
||||
// Only emit after everything is detached.
|
||||
this._detachments.next();
|
||||
@@ -142,7 +142,7 @@ export class OverlayRef implements PortalHost {
|
||||
}
|
||||
|
||||
this.detachBackdrop();
|
||||
this._portalHost.dispose();
|
||||
this._portalOutlet.dispose();
|
||||
this._attachments.complete();
|
||||
this._backdropClick.complete();
|
||||
this._detachments.next();
|
||||
@@ -153,7 +153,7 @@ export class OverlayRef implements PortalHost {
|
||||
* Checks whether the overlay has been attached.
|
||||
*/
|
||||
hasAttached(): boolean {
|
||||
return this._portalHost.hasAttached();
|
||||
return this._portalOutlet.hasAttached();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ The `overlay` package provides a way to open floating panels on the screen.
|
||||
Calling `overlay.create()` will return an `OverlayRef` instance. This instance is a handle for
|
||||
managing that specific overlay.
|
||||
|
||||
The `OverlayRef` _is_ a `PortalHost`- once created, content can be added by attaching a `Portal`.
|
||||
The `OverlayRef` _is_ a `PortalOutlet`- once created, content can be added by attaching a `Portal`.
|
||||
See the documentation on portals for further information.
|
||||
```ts
|
||||
const overlayRef = overlay.create();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Injector,
|
||||
NgZone,
|
||||
} from '@angular/core';
|
||||
import {DomPortalHost} from '@angular/cdk/portal';
|
||||
import {DomPortalOutlet} from '@angular/cdk/portal';
|
||||
import {OverlayConfig} from './overlay-config';
|
||||
import {OverlayRef} from './overlay-ref';
|
||||
import {OverlayPositionBuilder} from './position/overlay-position-builder';
|
||||
@@ -35,7 +35,7 @@ let defaultConfig = new OverlayConfig();
|
||||
* selects, etc. can all be built using overlays. The service should primarily be used by authors
|
||||
* of re-usable components rather than developers building end-user applications.
|
||||
*
|
||||
* An overlay *is* a PortalHost, so any kind of Portal can be loaded into one.
|
||||
* An overlay *is* a PortalOutlet, so any kind of Portal can be loaded into one.
|
||||
*/
|
||||
@Injectable()
|
||||
export class Overlay {
|
||||
@@ -57,8 +57,8 @@ export class Overlay {
|
||||
*/
|
||||
create(config: OverlayConfig = defaultConfig): OverlayRef {
|
||||
const pane = this._createPaneElement();
|
||||
const portalHost = this._createPortalHost(pane);
|
||||
return new OverlayRef(portalHost, pane, config, this._ngZone, this._keyboardDispatcher);
|
||||
const portalOutlet = this._createPortalOutlet(pane);
|
||||
return new OverlayRef(portalOutlet, pane, config, this._ngZone, this._keyboardDispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,12 +85,12 @@ export class Overlay {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DomPortalHost into which the overlay content can be loaded.
|
||||
* @param pane The DOM element to turn into a portal host.
|
||||
* @returns A portal host for the given DOM element.
|
||||
* Create a DomPortalOutlet into which the overlay content can be loaded.
|
||||
* @param pane The DOM element to turn into a portal outlet.
|
||||
* @returns A portal outlet for the given DOM element.
|
||||
*/
|
||||
private _createPortalHost(pane: HTMLElement): DomPortalHost {
|
||||
return new DomPortalHost(pane, this._componentFactoryResolver, this._appRef, this._injector);
|
||||
private _createPortalOutlet(pane: HTMLElement): DomPortalOutlet {
|
||||
return new DomPortalOutlet(pane, this._componentFactoryResolver, this._appRef, this._injector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@ import {
|
||||
ApplicationRef,
|
||||
Injector,
|
||||
} from '@angular/core';
|
||||
import {BasePortalHost, ComponentPortal, TemplatePortal} from './portal';
|
||||
import {BasePortalOutlet, ComponentPortal, TemplatePortal} from './portal';
|
||||
|
||||
|
||||
/**
|
||||
* A PortalHost for attaching portals to an arbitrary DOM element outside of the Angular
|
||||
* A PortalOutlet for attaching portals to an arbitrary DOM element outside of the Angular
|
||||
* application context.
|
||||
*/
|
||||
export class DomPortalHost extends BasePortalHost {
|
||||
export class DomPortalOutlet extends BasePortalOutlet {
|
||||
constructor(
|
||||
private _hostDomElement: Element,
|
||||
private _componentFactoryResolver: ComponentFactoryResolver,
|
||||
@@ -75,8 +75,9 @@ export class DomPortalHost extends BasePortalHost {
|
||||
viewRef.detectChanges();
|
||||
|
||||
// The method `createEmbeddedView` will add the view as a child of the viewContainer.
|
||||
// But for the DomPortalHost the view can be added everywhere in the DOM (e.g Overlay Container)
|
||||
// To move the view to the specified host element. We just re-append the existing root nodes.
|
||||
// But for the DomPortalOutlet the view can be added everywhere in the DOM
|
||||
// (e.g Overlay Container) To move the view to the specified host element. We just
|
||||
// re-append the existing root nodes.
|
||||
viewRef.rootNodes.forEach(rootNode => this._hostDomElement.appendChild(rootNode));
|
||||
|
||||
this.setDisposeFn((() => {
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
OnDestroy,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
import {Portal, TemplatePortal, ComponentPortal, BasePortalHost} from './portal';
|
||||
import {Portal, TemplatePortal, ComponentPortal, BasePortalOutlet} from './portal';
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,18 +36,18 @@ export class TemplatePortalDirective extends TemplatePortal<any> {
|
||||
|
||||
|
||||
/**
|
||||
* Directive version of a PortalHost. Because the directive *is* a PortalHost, portals can be
|
||||
* Directive version of a PortalOutlet. Because the directive *is* a PortalOutlet, portals can be
|
||||
* directly attached to it, enabling declarative use.
|
||||
*
|
||||
* Usage:
|
||||
* <ng-template [cdkPortalHost]="greeting"></ng-template>
|
||||
* <ng-template [cdkPortalOutlet]="greeting"></ng-template>
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[cdkPortalHost], [portalHost]',
|
||||
exportAs: 'cdkPortalHost',
|
||||
inputs: ['portal: cdkPortalHost']
|
||||
selector: '[cdkPortalOutlet], [cdkPortalHost], [portalHost]',
|
||||
exportAs: 'cdkPortalOutlet, cdkPortalHost',
|
||||
inputs: ['portal: cdkPortalOutlet']
|
||||
})
|
||||
export class PortalHostDirective extends BasePortalHost implements OnDestroy {
|
||||
export class PortalOutletDirective extends BasePortalOutlet implements OnDestroy {
|
||||
/** The attached portal. */
|
||||
private _portal: Portal<any> | null = null;
|
||||
|
||||
@@ -62,7 +62,12 @@ export class PortalHostDirective extends BasePortalHost implements OnDestroy {
|
||||
get _deprecatedPortal() { return this.portal; }
|
||||
set _deprecatedPortal(v) { this.portal = v; }
|
||||
|
||||
/** Portal associated with the Portal host. */
|
||||
/** @deprecated */
|
||||
@Input('cdkPortalHost')
|
||||
get _deprecatedPortalHost() { return this.portal; }
|
||||
set _deprecatedPortalHost(v) { this.portal = v; }
|
||||
|
||||
/** Portal associated with the Portal outlet. */
|
||||
get portal(): Portal<any> | null {
|
||||
return this._portal;
|
||||
}
|
||||
@@ -85,16 +90,16 @@ export class PortalHostDirective extends BasePortalHost implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the given ComponentPortal to this PortalHost using the ComponentFactoryResolver.
|
||||
* Attach the given ComponentPortal to this PortalOutlet using the ComponentFactoryResolver.
|
||||
*
|
||||
* @param portal Portal to be attached to the portal host.
|
||||
* @param portal Portal to be attached to the portal outlet.
|
||||
* @returns Reference to the created component.
|
||||
*/
|
||||
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
|
||||
portal.setAttachedHost(this);
|
||||
|
||||
// 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.
|
||||
// in the application tree. Otherwise use the location of this PortalOutlet.
|
||||
let viewContainerRef = portal.viewContainerRef != null ?
|
||||
portal.viewContainerRef :
|
||||
this._viewContainerRef;
|
||||
@@ -129,7 +134,7 @@ export class PortalHostDirective extends BasePortalHost implements OnDestroy {
|
||||
|
||||
|
||||
@NgModule({
|
||||
exports: [TemplatePortalDirective, PortalHostDirective],
|
||||
declarations: [TemplatePortalDirective, PortalHostDirective],
|
||||
exports: [TemplatePortalDirective, PortalOutletDirective],
|
||||
declarations: [TemplatePortalDirective, PortalOutletDirective],
|
||||
})
|
||||
export class PortalModule {}
|
||||
|
||||
@@ -26,8 +26,8 @@ export function throwPortalAlreadyAttachedError() {
|
||||
* Throws an exception when attempting to attach a portal to an already-disposed host.
|
||||
* @docs-private
|
||||
*/
|
||||
export function throwPortalHostAlreadyDisposedError() {
|
||||
throw Error('This PortalHost has already been disposed');
|
||||
export function throwPortalOutletAlreadyDisposedError() {
|
||||
throw Error('This PortalOutlet has already been disposed');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,16 +35,16 @@ export function throwPortalHostAlreadyDisposedError() {
|
||||
* @docs-private
|
||||
*/
|
||||
export function throwUnknownPortalTypeError() {
|
||||
throw Error('Attempting to attach an unknown Portal type. BasePortalHost accepts either ' +
|
||||
'a ComponentPortal or a TemplatePortal.');
|
||||
throw Error('Attempting to attach an unknown Portal type. BasePortalOutlet accepts either ' +
|
||||
'a ComponentPortal or a TemplatePortal.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception when attempting to attach a portal to a null host.
|
||||
* @docs-private
|
||||
*/
|
||||
export function throwNullPortalHostError() {
|
||||
throw Error('Attempting to attach a portal to a null PortalHost');
|
||||
export function throwNullPortalOutletError() {
|
||||
throw Error('Attempting to attach a portal to a null PortalOutlet');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,20 +3,20 @@ The `portals` package provides a flexible system for rendering dynamic content i
|
||||
### Portals
|
||||
A `Portal `is a piece of UI that can be dynamically rendered to an open slot on the page.
|
||||
|
||||
The "piece of UI" can be either a `Component` or a `TemplateRef` and the "open slot" is
|
||||
a `PortalHost`.
|
||||
The "piece of UI" can be either a `Component` or a `TemplateRef` and the "open slot" is
|
||||
a `PortalOutlet`.
|
||||
|
||||
Portals and PortalHosts are low-level building blocks that other concepts, such as overlays, are
|
||||
Portals and PortalOutlets are low-level building blocks that other concepts, such as overlays, are
|
||||
built upon.
|
||||
|
||||
##### `Portal<T>`
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `attach(PortalHost): Promise<T>` | Attaches the portal to a host. |
|
||||
| `attach(PortalOutlet): Promise<T>` | Attaches the portal to a host. |
|
||||
| `detach(): Promise<void>` | Detaches the portal from its host. |
|
||||
| `isAttached: boolean` | Whether the portal is attached. |
|
||||
|
||||
##### `PortalHost`
|
||||
##### `PortalOutlet`
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `attach(Portal): Promise<void>` | Attaches a portal to the host. |
|
||||
@@ -57,11 +57,11 @@ this.userSettingsPortal = new ComponentPortal(UserSettingsComponent);
|
||||
```
|
||||
|
||||
|
||||
##### `PortalHostDirective`
|
||||
Used to add a portal host to a template. `PortalHostDirective` *is* a `PortalHost`.
|
||||
##### `PortalOutletDirective`
|
||||
Used to add a portal outlet to a template. `PortalOutletDirective` *is* a `PortalOutlet`.
|
||||
|
||||
Usage:
|
||||
```html
|
||||
<!-- Attaches the `userSettingsPortal` from the previous example. -->
|
||||
<ng-template [cdkPortalHost]="userSettingsPortal"></ng-template>
|
||||
<ng-template [cdkPortalOutlet]="userSettingsPortal"></ng-template>
|
||||
```
|
||||
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
TemplateRef
|
||||
} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {TemplatePortalDirective, PortalHostDirective, PortalModule} from './portal-directives';
|
||||
import {TemplatePortalDirective, PortalOutletDirective, PortalModule} from './portal-directives';
|
||||
import {Portal, ComponentPortal, TemplatePortal} from './portal';
|
||||
import {DomPortalHost} from './dom-portal-host';
|
||||
import {DomPortalOutlet} from './dom-portal-outlet';
|
||||
|
||||
|
||||
describe('Portals', () => {
|
||||
@@ -28,7 +28,7 @@ describe('Portals', () => {
|
||||
TestBed.compileComponents();
|
||||
}));
|
||||
|
||||
describe('PortalHostDirective', () => {
|
||||
describe('PortalOutletDirective', () => {
|
||||
let fixture: ComponentFixture<PortalTestApp>;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -71,7 +71,7 @@ describe('Portals', () => {
|
||||
// using TemplatePortal.attach method to set context
|
||||
testAppComponent.selectedPortal = undefined;
|
||||
fixture.detectChanges();
|
||||
templatePortal.attach(testAppComponent.portalHost, {$implicit: {status: 'rotten'}});
|
||||
templatePortal.attach(testAppComponent.portalOutlet, {$implicit: {status: 'rotten'}});
|
||||
fixture.detectChanges();
|
||||
// Expect that the content of the attached portal is present and context given via the
|
||||
// attach method is projected
|
||||
@@ -90,7 +90,7 @@ describe('Portals', () => {
|
||||
// context, the latter should take precedence:
|
||||
testAppComponent.selectedPortal = undefined;
|
||||
fixture.detectChanges();
|
||||
templatePortal.attach(testAppComponent.portalHost, {$implicit: {status: 'rotten'}});
|
||||
templatePortal.attach(testAppComponent.portalOutlet, {$implicit: {status: 'rotten'}});
|
||||
fixture.detectChanges();
|
||||
// Expect that the content of the attached portal is present and and context given via the
|
||||
// attach method is projected and get precedence over constructor context
|
||||
@@ -223,32 +223,32 @@ describe('Portals', () => {
|
||||
testAppComponent.selectedPortal = new ComponentPortal(PizzaMsg);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(testAppComponent.portalHost.hasAttached()).toBe(true);
|
||||
expect(testAppComponent.portalHost.portal).toBe(testAppComponent.selectedPortal);
|
||||
expect(testAppComponent.portalOutlet.hasAttached()).toBe(true);
|
||||
expect(testAppComponent.portalOutlet.portal).toBe(testAppComponent.selectedPortal);
|
||||
|
||||
testAppComponent.selectedPortal = null;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(testAppComponent.portalHost.hasAttached()).toBe(false);
|
||||
expect(testAppComponent.portalHost.portal).toBeNull();
|
||||
expect(testAppComponent.portalOutlet.hasAttached()).toBe(false);
|
||||
expect(testAppComponent.portalOutlet.portal).toBeNull();
|
||||
});
|
||||
|
||||
it('should set the `portal` when attaching a component portal programmatically', () => {
|
||||
let testAppComponent = fixture.debugElement.componentInstance;
|
||||
let portal = new ComponentPortal(PizzaMsg);
|
||||
|
||||
testAppComponent.portalHost.attachComponentPortal(portal);
|
||||
testAppComponent.portalOutlet.attachComponentPortal(portal);
|
||||
|
||||
expect(testAppComponent.portalHost.portal).toBe(portal);
|
||||
expect(testAppComponent.portalOutlet.portal).toBe(portal);
|
||||
});
|
||||
|
||||
it('should set the `portal` when attaching a template portal programmatically', () => {
|
||||
let testAppComponent = fixture.debugElement.componentInstance;
|
||||
fixture.detectChanges();
|
||||
|
||||
testAppComponent.portalHost.attachTemplatePortal(testAppComponent.cakePortal);
|
||||
testAppComponent.portalOutlet.attachTemplatePortal(testAppComponent.cakePortal);
|
||||
|
||||
expect(testAppComponent.portalHost.portal).toBe(testAppComponent.cakePortal);
|
||||
expect(testAppComponent.portalOutlet.portal).toBe(testAppComponent.cakePortal);
|
||||
});
|
||||
|
||||
it('should clear the portal reference on destroy', () => {
|
||||
@@ -257,21 +257,21 @@ describe('Portals', () => {
|
||||
testAppComponent.selectedPortal = new ComponentPortal(PizzaMsg);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(testAppComponent.portalHost.portal).toBeTruthy();
|
||||
expect(testAppComponent.portalOutlet.portal).toBeTruthy();
|
||||
|
||||
fixture.destroy();
|
||||
|
||||
expect(testAppComponent.portalHost.portal).toBeNull();
|
||||
expect(testAppComponent.portalOutlet.portal).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('DomPortalHost', () => {
|
||||
describe('DomPortalOutlet', () => {
|
||||
let componentFactoryResolver: ComponentFactoryResolver;
|
||||
let someViewContainerRef: ViewContainerRef;
|
||||
let someInjector: Injector;
|
||||
let someFixture: ComponentFixture<any>;
|
||||
let someDomElement: HTMLElement;
|
||||
let host: DomPortalHost;
|
||||
let host: DomPortalOutlet;
|
||||
let injector: Injector;
|
||||
let appRef: ApplicationRef;
|
||||
|
||||
@@ -284,7 +284,7 @@ describe('Portals', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
someDomElement = document.createElement('div');
|
||||
host = new DomPortalHost(someDomElement, componentFactoryResolver, appRef, injector);
|
||||
host = new DomPortalOutlet(someDomElement, componentFactoryResolver, appRef, injector);
|
||||
|
||||
someFixture = TestBed.createComponent(ArbitraryViewContainerRefComponent);
|
||||
someViewContainerRef = someFixture.componentInstance.viewContainerRef;
|
||||
@@ -397,17 +397,17 @@ describe('Portals', () => {
|
||||
expect(componentInstance instanceof PizzaMsg)
|
||||
.toBe(true, 'Expected a PizzaMsg component to be created');
|
||||
expect(someDomElement.textContent)
|
||||
.toContain('Pizza', 'Expected the static string "Pizza" in the DomPortalHost.');
|
||||
.toContain('Pizza', 'Expected the static string "Pizza" in the DomPortalOutlet.');
|
||||
|
||||
componentInstance.snack = new Chocolate();
|
||||
someFixture.detectChanges();
|
||||
expect(someDomElement.textContent)
|
||||
.toContain('Chocolate', 'Expected the bound string "Chocolate" in the DomPortalHost');
|
||||
.toContain('Chocolate', 'Expected the bound string "Chocolate" in the DomPortalOutlet');
|
||||
|
||||
host.detach();
|
||||
|
||||
expect(someDomElement.innerHTML)
|
||||
.toBe('', 'Expected the DomPortalHost to be empty after detach');
|
||||
.toBe('', 'Expected the DomPortalOutlet to be empty after detach');
|
||||
});
|
||||
|
||||
it('should call the dispose function even if the host has no attached content', () => {
|
||||
@@ -457,12 +457,12 @@ class ArbitraryViewContainerRefComponent {
|
||||
}
|
||||
|
||||
|
||||
/** Test-bed component that contains a portal host and a couple of template portals. */
|
||||
/** Test-bed component that contains a portal outlet and a couple of template portals. */
|
||||
@Component({
|
||||
selector: 'portal-test',
|
||||
template: `
|
||||
<div class="portal-container">
|
||||
<ng-template [cdkPortalHost]="selectedPortal"></ng-template>
|
||||
<ng-template [cdkPortalOutlet]="selectedPortal"></ng-template>
|
||||
</div>
|
||||
|
||||
<ng-template cdk-portal>Cake</ng-template>
|
||||
@@ -481,7 +481,7 @@ class ArbitraryViewContainerRefComponent {
|
||||
})
|
||||
class PortalTestApp {
|
||||
@ViewChildren(TemplatePortalDirective) portals: QueryList<TemplatePortalDirective>;
|
||||
@ViewChild(PortalHostDirective) portalHost: PortalHostDirective;
|
||||
@ViewChild(PortalOutletDirective) portalOutlet: PortalOutletDirective;
|
||||
@ViewChild('templateRef', { read: TemplateRef }) templateRef: TemplateRef<any>;
|
||||
|
||||
selectedPortal: Portal<any>;
|
||||
|
||||
+17
-17
@@ -15,11 +15,11 @@ import {
|
||||
Injector
|
||||
} from '@angular/core';
|
||||
import {
|
||||
throwNullPortalHostError,
|
||||
throwNullPortalOutletError,
|
||||
throwPortalAlreadyAttachedError,
|
||||
throwNoPortalAttachedError,
|
||||
throwNullPortalError,
|
||||
throwPortalHostAlreadyDisposedError,
|
||||
throwPortalOutletAlreadyDisposedError,
|
||||
throwUnknownPortalTypeError
|
||||
} from './portal-errors';
|
||||
|
||||
@@ -30,15 +30,15 @@ export interface ComponentType<T> {
|
||||
|
||||
/**
|
||||
* A `Portal` is something that you want to render somewhere else.
|
||||
* It can be attach to / detached from a `PortalHost`.
|
||||
* It can be attach to / detached from a `PortalOutlet`.
|
||||
*/
|
||||
export abstract class Portal<T> {
|
||||
private _attachedHost: PortalHost | null;
|
||||
private _attachedHost: PortalOutlet | null;
|
||||
|
||||
/** Attach this portal to a host. */
|
||||
attach(host: PortalHost): T {
|
||||
attach(host: PortalOutlet): T {
|
||||
if (host == null) {
|
||||
throwNullPortalHostError();
|
||||
throwNullPortalOutletError();
|
||||
}
|
||||
|
||||
if (host.hasAttached()) {
|
||||
@@ -67,10 +67,10 @@ export abstract class Portal<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PortalHost reference without performing `attach()`. This is used directly by
|
||||
* the PortalHost when it is performing an `attach()` or `detach()`.
|
||||
* Sets the PortalOutlet reference without performing `attach()`. This is used directly by
|
||||
* the PortalOutlet when it is performing an `attach()` or `detach()`.
|
||||
*/
|
||||
setAttachedHost(host: PortalHost | null) {
|
||||
setAttachedHost(host: PortalOutlet | null) {
|
||||
this._attachedHost = host;
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
|
||||
|
||||
/**
|
||||
* [Optional] Where the attached component should live in Angular's *logical* component tree.
|
||||
* This is different from where the component *renders*, which is determined by the PortalHost.
|
||||
* This is different from where the component *renders*, which is determined by the PortalOutlet.
|
||||
* The origin is necessary when the host is outside of the Angular application context.
|
||||
*/
|
||||
viewContainerRef?: ViewContainerRef | null;
|
||||
@@ -130,11 +130,11 @@ export class TemplatePortal<C> extends Portal<C> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the the portal to the provided `PortalHost`.
|
||||
* Attach the the portal to the provided `PortalOutlet`.
|
||||
* When a context is provided it will override the `context` property of the `TemplatePortal`
|
||||
* instance.
|
||||
*/
|
||||
attach(host: PortalHost, context: C | undefined = this.context): C {
|
||||
attach(host: PortalOutlet, context: C | undefined = this.context): C {
|
||||
this.context = context;
|
||||
return super.attach(host);
|
||||
}
|
||||
@@ -147,9 +147,9 @@ export class TemplatePortal<C> extends Portal<C> {
|
||||
|
||||
|
||||
/**
|
||||
* A `PortalHost` is an space that can contain a single `Portal`.
|
||||
* A `PortalOutlet` is an space that can contain a single `Portal`.
|
||||
*/
|
||||
export interface PortalHost {
|
||||
export interface PortalOutlet {
|
||||
attach(portal: Portal<any>): any;
|
||||
|
||||
detach(): any;
|
||||
@@ -161,10 +161,10 @@ export interface PortalHost {
|
||||
|
||||
|
||||
/**
|
||||
* Partial implementation of PortalHost that handles attaching
|
||||
* Partial implementation of PortalOutlet that handles attaching
|
||||
* ComponentPortal and TemplatePortal.
|
||||
*/
|
||||
export abstract class BasePortalHost implements PortalHost {
|
||||
export abstract class BasePortalOutlet implements PortalOutlet {
|
||||
/** The portal currently attached to the host. */
|
||||
private _attachedPortal: Portal<any> | null;
|
||||
|
||||
@@ -190,7 +190,7 @@ export abstract class BasePortalHost implements PortalHost {
|
||||
}
|
||||
|
||||
if (this._isDisposed) {
|
||||
throwPortalHostAlreadyDisposedError();
|
||||
throwPortalOutletAlreadyDisposedError();
|
||||
}
|
||||
|
||||
if (portal instanceof ComponentPortal) {
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
*/
|
||||
|
||||
export * from './portal';
|
||||
export * from './dom-portal-host';
|
||||
export * from './dom-portal-outlet';
|
||||
export * from './portal-directives';
|
||||
export * from './portal-injector';
|
||||
|
||||
export {DomPortalOutlet as DomPortalHost} from './dom-portal-outlet';
|
||||
export {PortalOutletDirective as PortalHostDirective} from './portal-directives';
|
||||
export {PortalOutlet as PortalHost, BasePortalOutlet as BasePortalHost} from './portal';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<h2> The portal host is here: </h2>
|
||||
<div class="demo-portal-host">
|
||||
<ng-template [cdkPortalHost]="selectedPortal"></ng-template>
|
||||
<h2> The portal outlet is here: </h2>
|
||||
<div class="demo-portal-outlet">
|
||||
<ng-template [cdkPortalOutlet]="selectedPortal"></ng-template>
|
||||
</div>
|
||||
|
||||
<button type="button" (click)="selectedPortal = programmingJoke">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.demo-portal-host {
|
||||
.demo-portal-outlet {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border: 1px dashed black;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<ng-template cdkPortalHost></ng-template>
|
||||
<ng-template cdkPortalOutlet></ng-template>
|
||||
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
import {animate, AnimationEvent, state, style, transition, trigger} from '@angular/animations';
|
||||
import {DOCUMENT} from '@angular/platform-browser';
|
||||
import {
|
||||
BasePortalHost,
|
||||
BasePortalOutlet,
|
||||
ComponentPortal,
|
||||
PortalHostDirective,
|
||||
PortalOutletDirective,
|
||||
TemplatePortal
|
||||
} from '@angular/cdk/portal';
|
||||
import {FocusTrap, FocusTrapFactory} from '@angular/cdk/a11y';
|
||||
@@ -33,7 +33,7 @@ import {MatDialogConfig} from './dialog-config';
|
||||
|
||||
/**
|
||||
* Throws an exception for the case when a ComponentPortal is
|
||||
* attached to a DomPortalHost without an origin.
|
||||
* attached to a DomPortalOutlet without an origin.
|
||||
* @docs-private
|
||||
*/
|
||||
export function throwMatDialogContentAlreadyAttachedError() {
|
||||
@@ -78,9 +78,9 @@ export function throwMatDialogContentAlreadyAttachedError() {
|
||||
'(@slideDialog.done)': '_onAnimationDone($event)',
|
||||
},
|
||||
})
|
||||
export class MatDialogContainer extends BasePortalHost {
|
||||
/** The portal host inside of this container into which the dialog content will be loaded. */
|
||||
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;
|
||||
export class MatDialogContainer extends BasePortalOutlet {
|
||||
/** The portal outlet inside of this container into which the dialog content will be loaded. */
|
||||
@ViewChild(PortalOutletDirective) _portalOutlet: PortalOutletDirective;
|
||||
|
||||
/** The class that traps and manages focus within the dialog. */
|
||||
private _focusTrap: FocusTrap;
|
||||
@@ -117,12 +117,12 @@ export class MatDialogContainer extends BasePortalHost {
|
||||
* @param portal Portal to be attached as the dialog content.
|
||||
*/
|
||||
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
|
||||
if (this._portalHost.hasAttached()) {
|
||||
if (this._portalOutlet.hasAttached()) {
|
||||
throwMatDialogContentAlreadyAttachedError();
|
||||
}
|
||||
|
||||
this._savePreviouslyFocusedElement();
|
||||
return this._portalHost.attachComponentPortal(portal);
|
||||
return this._portalOutlet.attachComponentPortal(portal);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,12 +130,12 @@ export class MatDialogContainer extends BasePortalHost {
|
||||
* @param portal Portal to be attached as the dialog content.
|
||||
*/
|
||||
attachTemplatePortal<C>(portal: TemplatePortal<C>): EmbeddedViewRef<C> {
|
||||
if (this._portalHost.hasAttached()) {
|
||||
if (this._portalOutlet.hasAttached()) {
|
||||
throwMatDialogContentAlreadyAttachedError();
|
||||
}
|
||||
|
||||
this._savePreviouslyFocusedElement();
|
||||
return this._portalHost.attachTemplatePortal(portal);
|
||||
return this._portalOutlet.attachTemplatePortal(portal);
|
||||
}
|
||||
|
||||
/** Moves the focus inside the focus trap. */
|
||||
|
||||
@@ -1 +1 @@
|
||||
<ng-template cdkPortalHost></ng-template>
|
||||
<ng-template cdkPortalOutlet></ng-template>
|
||||
|
||||
@@ -28,9 +28,9 @@ import {
|
||||
AnimationEvent,
|
||||
} from '@angular/animations';
|
||||
import {
|
||||
BasePortalHost,
|
||||
BasePortalOutlet,
|
||||
ComponentPortal,
|
||||
PortalHostDirective,
|
||||
PortalOutletDirective,
|
||||
} from '@angular/cdk/portal';
|
||||
import {first} from 'rxjs/operators';
|
||||
import {AnimationCurves, AnimationDurations} from '@angular/material/core';
|
||||
@@ -71,12 +71,12 @@ export const HIDE_ANIMATION =
|
||||
])
|
||||
],
|
||||
})
|
||||
export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy {
|
||||
/** Whether the component has been destroyed. */
|
||||
private _destroyed = false;
|
||||
|
||||
/** The portal host inside of this container into which the snack bar content will be loaded. */
|
||||
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;
|
||||
/** The portal outlet inside of this container into which the snack bar content will be loaded. */
|
||||
@ViewChild(PortalOutletDirective) _portalOutlet: PortalOutletDirective;
|
||||
|
||||
/** Subject for notifying that the snack bar has exited from view. */
|
||||
_onExit: Subject<any> = new Subject();
|
||||
@@ -100,7 +100,7 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
|
||||
/** Attach a component portal as content to this snack bar container. */
|
||||
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
|
||||
if (this._portalHost.hasAttached()) {
|
||||
if (this._portalOutlet.hasAttached()) {
|
||||
throw Error('Attempting to attach snack bar content after content is already attached');
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
this._renderer.addClass(this._elementRef.nativeElement, 'mat-snack-bar-top');
|
||||
}
|
||||
|
||||
return this._portalHost.attachComponentPortal(portal);
|
||||
return this._portalOutlet.attachComponentPortal(portal);
|
||||
}
|
||||
|
||||
/** Attach a template portal as content to this snack bar container. */
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
[@translateTab]="_position"
|
||||
(@translateTab.start)="_onTranslateTabStarted($event)"
|
||||
(@translateTab.done)="_onTranslateTabComplete($event)">
|
||||
<ng-template cdkPortalHost></ng-template>
|
||||
<ng-template cdkPortalOutlet></ng-template>
|
||||
</div>
|
||||
|
||||
@@ -156,16 +156,16 @@ describe('MatTabBody', () => {
|
||||
it('should attach the content when centered and detach when not', fakeAsync(() => {
|
||||
fixture.componentInstance.position = 1;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.tabBody._portalHost.hasAttached()).toBe(false);
|
||||
expect(fixture.componentInstance.tabBody._portalOutlet.hasAttached()).toBe(false);
|
||||
|
||||
fixture.componentInstance.position = 0;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.tabBody._portalHost.hasAttached()).toBe(true);
|
||||
expect(fixture.componentInstance.tabBody._portalOutlet.hasAttached()).toBe(true);
|
||||
|
||||
fixture.componentInstance.position = 1;
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks(); // Finish animation and let it detach in animation done handler
|
||||
expect(fixture.componentInstance.tabBody._portalHost.hasAttached()).toBe(false);
|
||||
expect(fixture.componentInstance.tabBody._portalOutlet.hasAttached()).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
transition,
|
||||
AnimationEvent,
|
||||
} from '@angular/animations';
|
||||
import {TemplatePortal, PortalHostDirective} from '@angular/cdk/portal';
|
||||
import {TemplatePortal, PortalOutletDirective} from '@angular/cdk/portal';
|
||||
import {Directionality, Direction} from '@angular/cdk/bidi';
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ export type MatTabBodyOriginState = 'left' | 'right';
|
||||
]
|
||||
})
|
||||
export class MatTabBody implements OnInit, AfterViewChecked {
|
||||
/** The portal host inside of this container into which the tab body content will be loaded. */
|
||||
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;
|
||||
/** The portal outlet inside of this container into which the tab body content will be loaded. */
|
||||
@ViewChild(PortalOutletDirective) _portalOutlet: PortalOutletDirective;
|
||||
|
||||
/** Event emitted when the tab begins to animate towards the center as the active tab. */
|
||||
@Output() _onCentering: EventEmitter<number> = new EventEmitter<number>();
|
||||
@@ -144,8 +144,8 @@ export class MatTabBody implements OnInit, AfterViewChecked {
|
||||
* content if it is not already attached.
|
||||
*/
|
||||
ngAfterViewChecked() {
|
||||
if (this._isCenterPosition(this._position) && !this._portalHost.hasAttached()) {
|
||||
this._portalHost.attach(this._content);
|
||||
if (this._isCenterPosition(this._position) && !this._portalOutlet.hasAttached()) {
|
||||
this._portalOutlet.attach(this._content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export class MatTabBody implements OnInit, AfterViewChecked {
|
||||
_onTranslateTabComplete(e: AnimationEvent) {
|
||||
// If the end state is that the tab is not centered, then detach the content.
|
||||
if (!this._isCenterPosition(e.toState) && !this._isCenterPosition(this._position)) {
|
||||
this._portalHost.detach();
|
||||
this._portalOutlet.detach();
|
||||
}
|
||||
|
||||
// If the transition to the center is complete, emit an event.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- If there is a label template, use it. -->
|
||||
<ng-template [ngIf]="tab.templateLabel">
|
||||
<ng-template [cdkPortalHost]="tab.templateLabel"></ng-template>
|
||||
<ng-template [cdkPortalOutlet]="tab.templateLabel"></ng-template>
|
||||
</ng-template>
|
||||
|
||||
<!-- If there is not a label template, fall back to the text label. -->
|
||||
|
||||
Reference in New Issue
Block a user