fix(portal): detect changes for portal hostview while before attaching. (#4370)

This commit is contained in:
Joey Perrott
2017-06-07 11:00:07 -07:00
committed by Andrew Seguin
parent 1f93cdb247
commit 28d2ddd098
4 changed files with 33 additions and 17 deletions
+3 -7
View File
@@ -29,21 +29,17 @@ export class DomPortalHost extends BasePortalHost {
*/
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component);
let componentRef: ComponentRef<T>;
let componentRef = componentFactory.create(portal.injector || this._defaultInjector);
componentRef.hostView.detectChanges();
// If the portal specifies a ViewContainerRef, we will use that as the attachment point
// for the component (in terms of Angular's component tree, not rendering).
// When the ViewContainerRef is missing, we use the factory to create the component directly
// and then manually attach the view to the application.
if (portal.viewContainerRef) {
componentRef = portal.viewContainerRef.createComponent(
componentFactory,
portal.viewContainerRef.length,
portal.injector || portal.viewContainerRef.parentInjector);
portal.viewContainerRef.insert(componentRef.hostView);
this.setDisposeFn(() => componentRef.destroy());
} else {
componentRef = componentFactory.create(portal.injector || this._defaultInjector);
this._appRef.attachView(componentRef.hostView);
this.setDisposeFn(() => {
this._appRef.detachView(componentRef.hostView);
+21 -1
View File
@@ -368,6 +368,12 @@ describe('Portals', () => {
expect(spy).toHaveBeenCalled();
});
it('should run change detection in the created component when a ComponentPortal is attached',
() => {
host.attach(new ComponentPortal(ComponentWithBoundVariable, someViewContainerRef));
expect(someDomElement.textContent).toContain('initial value');
});
});
});
@@ -404,6 +410,15 @@ class ArbitraryViewContainerRefComponent {
constructor(public viewContainerRef: ViewContainerRef, public injector: Injector) { }
}
/** Simple component with a bound variable in the template */
@Component({
selector: 'bound-text',
template: '<p>{{text}}</p>'
})
class ComponentWithBoundVariable {
text: string = 'initial value';
}
/** Test-bed component that contains a portal host and a couple of template portals. */
@Component({
@@ -453,7 +468,12 @@ class PortalTestApp {
// Create a real (non-test) NgModule as a workaround for
// https://github.com/angular/angular/issues/10760
const TEST_COMPONENTS = [PortalTestApp, ArbitraryViewContainerRefComponent, PizzaMsg];
const TEST_COMPONENTS = [
PortalTestApp,
ArbitraryViewContainerRefComponent,
PizzaMsg,
ComponentWithBoundVariable
];
@NgModule({
imports: [CommonModule, PortalModule],
exports: TEST_COMPONENTS,
+8 -8
View File
@@ -1,10 +1,10 @@
<md-calendar cdkTrapFocus
[id]="datepicker.id"
[startAt]="datepicker.startAt"
[startView]="datepicker.startView"
[minDate]="datepicker._minDate"
[maxDate]="datepicker._maxDate"
[dateFilter]="datepicker._dateFilter"
[selected]="datepicker._selected"
(selectedChange)="datepicker._selectAndClose($event)">
[id]="datepicker?.id"
[startAt]="datepicker?.startAt"
[startView]="datepicker?.startView"
[minDate]="datepicker?._minDate"
[maxDate]="datepicker?._maxDate"
[dateFilter]="datepicker?._dateFilter"
[selected]="datepicker?._selected"
(selectedChange)="datepicker?._selectAndClose($event)">
</md-calendar>
+1 -1
View File
@@ -49,7 +49,7 @@ let datepickerUid = 0;
styleUrls: ['datepicker-content.css'],
host: {
'class': 'mat-datepicker-content',
'[class.mat-datepicker-content-touch]': 'datepicker.touchUi',
'[class.mat-datepicker-content-touch]': 'datepicker?.touchUi',
'(keydown)': '_handleKeydown($event)',
},
encapsulation: ViewEncapsulation.None,