fix(upgrade): correctly handle downgraded `OnPush` components (#22209)

Fixes #14286

PR Close #22209
This commit is contained in:
Shannon Dunn 2018-02-13 17:13:47 -05:00 committed by Alex Rickabaugh
parent 7a1c43733b
commit ad9ce5cb41
2 changed files with 50 additions and 1 deletions

View File

@ -25,6 +25,7 @@ export class DowngradeComponentAdapter {
private componentRef: ComponentRef<any>;
private component: any;
private changeDetector: ChangeDetectorRef;
private viewChangeDetector: ChangeDetectorRef;
constructor(
private element: angular.IAugmentedJQuery, private attrs: angular.IAttributes,
@ -60,6 +61,7 @@ export class DowngradeComponentAdapter {
this.componentRef =
this.componentFactory.create(childInjector, projectableNodes, this.element[0]);
this.viewChangeDetector = this.componentRef.injector.get(ChangeDetectorRef);
this.changeDetector = this.componentRef.changeDetectorRef;
this.component = this.componentRef.instance;
@ -139,6 +141,8 @@ export class DowngradeComponentAdapter {
(<OnChanges>this.component).ngOnChanges(inputChanges !);
}
this.viewChangeDetector.markForCheck();
// If opted out of propagating digests, invoke change detection when inputs change.
if (!propagateDigest) {
detectChanges();

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, Directive, ElementRef, EventEmitter, Injector, Input, NgModule, NgModuleRef, OnChanges, OnDestroy, Output, SimpleChanges, destroyPlatform} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, Directive, ElementRef, EventEmitter, Injector, Input, NgModule, NgModuleRef, OnChanges, OnDestroy, Output, SimpleChanges, destroyPlatform} from '@angular/core';
import {async, fakeAsync, tick} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -148,6 +148,51 @@ withEachNg1Version(() => {
});
}));
it('should bind properties to onpush components', async(() => {
const ng1Module =
angular.module('ng1', []).value('$exceptionHandler', (err: any) => {
throw err;
}).run(($rootScope: angular.IScope) => {
$rootScope['dataB'] = 'B';
});
@Component({
selector: 'ng2',
inputs: ['oneWayB'],
template: 'oneWayB: {{oneWayB}}',
changeDetection: ChangeDetectionStrategy.OnPush
})
class Ng2Component {
ngOnChangesCount = 0;
oneWayB = '?';
}
ng1Module.directive('ng2', downgradeComponent({
component: Ng2Component,
}));
@NgModule({
declarations: [Ng2Component],
entryComponents: [Ng2Component],
imports: [BrowserModule, UpgradeModule]
})
class Ng2Module {
ngDoBootstrap() {}
}
const element = html(`
<div>
<ng2 [one-way-b]="dataB"></ng2>
</div>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
expect(multiTrim(document.body.textContent)).toEqual('oneWayB: B');
$apply(upgrade, 'dataB= "everyone"');
expect(multiTrim(document.body.textContent)).toEqual('oneWayB: everyone');
});
}));
it('should support two-way binding and event listener', async(() => {
const listenerSpy = jasmine.createSpy('$rootScope.listener');
const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => {