fix(ivy): fix property names of ngOnChanges (#27714)
- #reslove FW-812 - #reslove FW-844 PR Close #27714
This commit is contained in:
parent
4774a1abff
commit
1c93afe956
@ -110,7 +110,7 @@ function baseDirectiveFields(
|
|||||||
meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool, hostVarsCount));
|
meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool, hostVarsCount));
|
||||||
|
|
||||||
// e.g 'inputs: {a: 'a'}`
|
// e.g 'inputs: {a: 'a'}`
|
||||||
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs));
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true));
|
||||||
|
|
||||||
// e.g 'outputs: {a: 'a'}`
|
// e.g 'outputs: {a: 'a'}`
|
||||||
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
|
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
|
||||||
|
@ -67,20 +67,36 @@ export function asLiteral(value: any): o.Expression {
|
|||||||
return o.literal(value, o.INFERRED_TYPE);
|
return o.literal(value, o.INFERRED_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function conditionallyCreateMapObjectLiteral(keys: {[key: string]: string | string[]}):
|
export function conditionallyCreateMapObjectLiteral(
|
||||||
o.Expression|null {
|
keys: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression|null {
|
||||||
if (Object.getOwnPropertyNames(keys).length > 0) {
|
if (Object.getOwnPropertyNames(keys).length > 0) {
|
||||||
return mapToExpression(keys);
|
return mapToExpression(keys, keepDeclared);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapToExpression(map: {[key: string]: any}): o.Expression {
|
function mapToExpression(
|
||||||
|
map: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression {
|
||||||
return o.literalMap(Object.getOwnPropertyNames(map).map(key => {
|
return o.literalMap(Object.getOwnPropertyNames(map).map(key => {
|
||||||
// canonical syntax: `dirProp: elProp`
|
// canonical syntax: `dirProp: publicProp`
|
||||||
// if there is no `:`, use dirProp = elProp
|
// if there is no `:`, use dirProp = elProp
|
||||||
const parts = splitAtColon(key, [key, map[key]]);
|
const value = map[key];
|
||||||
return {key: parts[0], quoted: false, value: asLiteral(parts[1])};
|
let declaredName: string;
|
||||||
|
let publicName: string;
|
||||||
|
let minifiedName: string;
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
[publicName, declaredName] = value;
|
||||||
|
} else {
|
||||||
|
[declaredName, publicName] = splitAtColon(key, [key, value]);
|
||||||
|
}
|
||||||
|
minifiedName = declaredName;
|
||||||
|
return {
|
||||||
|
key: minifiedName,
|
||||||
|
quoted: false,
|
||||||
|
value: (keepDeclared && publicName !== declaredName) ?
|
||||||
|
o.literalArr([asLiteral(publicName), asLiteral(declaredName)]) :
|
||||||
|
asLiteral(publicName)
|
||||||
|
};
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,8 +345,8 @@ export function defineNgModule<T>(def: {type: T} & Partial<NgModuleDef<T>>): nev
|
|||||||
* @Input()
|
* @Input()
|
||||||
* propName1: string;
|
* propName1: string;
|
||||||
*
|
*
|
||||||
* @Input('publicName')
|
* @Input('publicName2')
|
||||||
* propName2: number;
|
* declaredPropName2: number;
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@ -354,26 +354,35 @@ export function defineNgModule<T>(def: {type: T} & Partial<NgModuleDef<T>>): nev
|
|||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* a0: 'propName1',
|
* propName1: 'propName1',
|
||||||
* b1: ['publicName', 'propName2'],
|
* declaredPropName2: ['publicName2', 'declaredPropName2'],
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* becomes
|
* which is than translated by the minifier as:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* 'propName1': 'a0',
|
* minifiedPropName1: 'propName1',
|
||||||
* 'publicName': 'b1'
|
* minifiedPropName2: ['publicName2', 'declaredPropName2'],
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Optionally the function can take `secondary` which will result in:
|
* becomes: (public name => minifiedName)
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* 'propName1': 'a0',
|
* 'propName1': 'minifiedPropName1',
|
||||||
* 'propName2': 'b1'
|
* 'publicName2': 'minifiedPropName2',
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Optionally the function can take `secondary` which will result in: (public name => declared name)
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* {
|
||||||
|
* 'propName1': 'propName1',
|
||||||
|
* 'publicName2': 'declaredPropName2',
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@ -384,7 +393,7 @@ function invertObject(obj: any, secondary?: any): any {
|
|||||||
const newLookup: any = {};
|
const newLookup: any = {};
|
||||||
for (const minifiedKey in obj) {
|
for (const minifiedKey in obj) {
|
||||||
if (obj.hasOwnProperty(minifiedKey)) {
|
if (obj.hasOwnProperty(minifiedKey)) {
|
||||||
let publicName = obj[minifiedKey];
|
let publicName: string = obj[minifiedKey];
|
||||||
let declaredName = publicName;
|
let declaredName = publicName;
|
||||||
if (Array.isArray(publicName)) {
|
if (Array.isArray(publicName)) {
|
||||||
declaredName = publicName[1];
|
declaredName = publicName[1];
|
||||||
@ -392,7 +401,7 @@ function invertObject(obj: any, secondary?: any): any {
|
|||||||
}
|
}
|
||||||
newLookup[publicName] = minifiedKey;
|
newLookup[publicName] = minifiedKey;
|
||||||
if (secondary) {
|
if (secondary) {
|
||||||
(secondary[declaredName] = minifiedKey);
|
(secondary[publicName] = declaredName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,13 @@ type OnChangesExpando = OnChanges & {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function NgOnChangesFeature<T>(definition: DirectiveDef<T>): void {
|
export function NgOnChangesFeature<T>(definition: DirectiveDef<T>): void {
|
||||||
const declaredToMinifiedInputs = definition.declaredInputs;
|
const publicToDeclaredInputs = definition.declaredInputs;
|
||||||
|
const publicToMinifiedInputs = definition.inputs;
|
||||||
const proto = definition.type.prototype;
|
const proto = definition.type.prototype;
|
||||||
for (const declaredName in declaredToMinifiedInputs) {
|
for (const publicName in publicToDeclaredInputs) {
|
||||||
if (declaredToMinifiedInputs.hasOwnProperty(declaredName)) {
|
if (publicToDeclaredInputs.hasOwnProperty(publicName)) {
|
||||||
const minifiedKey = declaredToMinifiedInputs[declaredName];
|
const minifiedKey = publicToMinifiedInputs[publicName];
|
||||||
|
const declaredKey = publicToDeclaredInputs[publicName];
|
||||||
const privateMinKey = PRIVATE_PREFIX + minifiedKey;
|
const privateMinKey = PRIVATE_PREFIX + minifiedKey;
|
||||||
|
|
||||||
// Walk the prototype chain to see if we find a property descriptor
|
// Walk the prototype chain to see if we find a property descriptor
|
||||||
@ -72,12 +74,12 @@ export function NgOnChangesFeature<T>(definition: DirectiveDef<T>): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isFirstChange = !this.hasOwnProperty(privateMinKey);
|
const isFirstChange = !this.hasOwnProperty(privateMinKey);
|
||||||
const currentChange = simpleChanges[declaredName];
|
const currentChange = simpleChanges[declaredKey];
|
||||||
|
|
||||||
if (currentChange) {
|
if (currentChange) {
|
||||||
currentChange.currentValue = value;
|
currentChange.currentValue = value;
|
||||||
} else {
|
} else {
|
||||||
simpleChanges[declaredName] =
|
simpleChanges[declaredKey] =
|
||||||
new SimpleChange(this[privateMinKey], value, isFirstChange);
|
new SimpleChange(this[privateMinKey], value, isFirstChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,10 +84,10 @@ describe('InheritDefinitionFeature', () => {
|
|||||||
qux: 'subQux',
|
qux: 'subQux',
|
||||||
});
|
});
|
||||||
expect(subDef.declaredInputs).toEqual({
|
expect(subDef.declaredInputs).toEqual({
|
||||||
declaredFoo: 'superFoo',
|
foo: 'declaredFoo',
|
||||||
bar: 'superBar',
|
bar: 'bar',
|
||||||
baz: 'subBaz',
|
baz: 'baz',
|
||||||
qux: 'subQux',
|
qux: 'qux',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ describe('InheritDefinitionFeature', () => {
|
|||||||
expect(subDef.declaredInputs).toEqual({
|
expect(subDef.declaredInputs).toEqual({
|
||||||
input1: 'input1',
|
input1: 'input1',
|
||||||
input2: 'input2',
|
input2: 'input2',
|
||||||
input3: 'input3',
|
alias3: 'input3',
|
||||||
input4: 'input4',
|
input4: 'input4',
|
||||||
input5: 'input5',
|
input5: 'input5',
|
||||||
});
|
});
|
||||||
|
@ -264,7 +264,7 @@ ivyEnabled && describe('render3 jit', () => {
|
|||||||
|
|
||||||
const InputCompAny = InputComp as any;
|
const InputCompAny = InputComp as any;
|
||||||
expect(InputCompAny.ngComponentDef.inputs).toEqual({publicName: 'privateName'});
|
expect(InputCompAny.ngComponentDef.inputs).toEqual({publicName: 'privateName'});
|
||||||
expect(InputCompAny.ngComponentDef.declaredInputs).toEqual({privateName: 'privateName'});
|
expect(InputCompAny.ngComponentDef.declaredInputs).toEqual({publicName: 'privateName'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add @Input properties to a directive', () => {
|
it('should add @Input properties to a directive', () => {
|
||||||
@ -277,7 +277,7 @@ ivyEnabled && describe('render3 jit', () => {
|
|||||||
|
|
||||||
const InputDirAny = InputDir as any;
|
const InputDirAny = InputDir as any;
|
||||||
expect(InputDirAny.ngDirectiveDef.inputs).toEqual({publicName: 'privateName'});
|
expect(InputDirAny.ngDirectiveDef.inputs).toEqual({publicName: 'privateName'});
|
||||||
expect(InputDirAny.ngDirectiveDef.declaredInputs).toEqual({privateName: 'privateName'});
|
expect(InputDirAny.ngDirectiveDef.declaredInputs).toEqual({publicName: 'privateName'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add ngBaseDef to types with @Input properties', () => {
|
it('should add ngBaseDef to types with @Input properties', () => {
|
||||||
|
@ -1915,194 +1915,189 @@ withEachNg1Version(() => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fixmeIvy(
|
it('should call `$onChanges()` on binding destination', fakeAsync(() => {
|
||||||
'FW-844: Directive input bindings cannot be assigned after the `@Directive` decorator has been compiled')
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
.it('should call `$onChanges()` on binding destination', fakeAsync(() => {
|
const $onChangesControllerSpyA = jasmine.createSpy('$onChangesControllerA');
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const $onChangesControllerSpyB = jasmine.createSpy('$onChangesControllerB');
|
||||||
const $onChangesControllerSpyA = jasmine.createSpy('$onChangesControllerA');
|
const $onChangesScopeSpy = jasmine.createSpy('$onChangesScope');
|
||||||
const $onChangesControllerSpyB = jasmine.createSpy('$onChangesControllerB');
|
let ng2Instance: any;
|
||||||
const $onChangesScopeSpy = jasmine.createSpy('$onChangesScope');
|
|
||||||
let ng2Instance: any;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ng2',
|
selector: 'ng2',
|
||||||
template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>'
|
template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>'
|
||||||
})
|
})
|
||||||
class Ng2Component {
|
class Ng2Component {
|
||||||
constructor() { ng2Instance = this; }
|
constructor() { ng2Instance = this; }
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.module('ng1', [])
|
angular.module('ng1', [])
|
||||||
.directive('ng1A', () => ({
|
.directive('ng1A', () => ({
|
||||||
template: '',
|
template: '',
|
||||||
scope: {valA: '<'},
|
scope: {valA: '<'},
|
||||||
bindToController: true,
|
bindToController: true,
|
||||||
controllerAs: '$ctrl',
|
controllerAs: '$ctrl',
|
||||||
controller: function($scope: angular.IScope) {
|
controller: function($scope: angular.IScope) {
|
||||||
this.$onChanges = $onChangesControllerSpyA;
|
this.$onChanges = $onChangesControllerSpyA;
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.directive('ng1B', () => ({
|
.directive(
|
||||||
template: '',
|
'ng1B',
|
||||||
scope: {valB: '<'},
|
() => ({
|
||||||
bindToController: false,
|
template: '',
|
||||||
controllerAs: '$ctrl',
|
scope: {valB: '<'},
|
||||||
controller: class {
|
bindToController: false,
|
||||||
$onChanges(changes: SimpleChanges) {
|
controllerAs: '$ctrl',
|
||||||
$onChangesControllerSpyB(changes);
|
controller: class {
|
||||||
}
|
$onChanges(changes: SimpleChanges) { $onChangesControllerSpyB(changes); }
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component))
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component))
|
||||||
.run(($rootScope: angular.IRootScopeService) => {
|
.run(($rootScope: angular.IRootScopeService) => {
|
||||||
Object.getPrototypeOf($rootScope).$onChanges = $onChangesScopeSpy;
|
Object.getPrototypeOf($rootScope).$onChanges = $onChangesScopeSpy;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'),
|
adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'),
|
||||||
Ng2Component
|
Ng2Component
|
||||||
],
|
],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
})
|
||||||
class Ng2Module {
|
class Ng2Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
const element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
// Initial `$onChanges()` call
|
// Initial `$onChanges()` call
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
expect($onChangesControllerSpyA.calls.count()).toBe(1);
|
expect($onChangesControllerSpyA.calls.count()).toBe(1);
|
||||||
expect($onChangesControllerSpyA.calls.argsFor(0)[0]).toEqual({
|
expect($onChangesControllerSpyA.calls.argsFor(0)[0]).toEqual({
|
||||||
valA: jasmine.any(SimpleChange)
|
valA: jasmine.any(SimpleChange)
|
||||||
});
|
});
|
||||||
|
|
||||||
expect($onChangesControllerSpyB).not.toHaveBeenCalled();
|
expect($onChangesControllerSpyB).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect($onChangesScopeSpy.calls.count()).toBe(1);
|
expect($onChangesScopeSpy.calls.count()).toBe(1);
|
||||||
expect($onChangesScopeSpy.calls.argsFor(0)[0]).toEqual({
|
expect($onChangesScopeSpy.calls.argsFor(0)[0]).toEqual({
|
||||||
valB: jasmine.any(SimpleChange)
|
valB: jasmine.any(SimpleChange)
|
||||||
});
|
});
|
||||||
|
|
||||||
$onChangesControllerSpyA.calls.reset();
|
$onChangesControllerSpyA.calls.reset();
|
||||||
$onChangesControllerSpyB.calls.reset();
|
$onChangesControllerSpyB.calls.reset();
|
||||||
$onChangesScopeSpy.calls.reset();
|
$onChangesScopeSpy.calls.reset();
|
||||||
|
|
||||||
// `$onChanges()` call after a change
|
// `$onChanges()` call after a change
|
||||||
ng2Instance.val = 'new value';
|
ng2Instance.val = 'new value';
|
||||||
tick();
|
tick();
|
||||||
ref.ng1RootScope.$digest();
|
ref.ng1RootScope.$digest();
|
||||||
|
|
||||||
expect($onChangesControllerSpyA.calls.count()).toBe(1);
|
expect($onChangesControllerSpyA.calls.count()).toBe(1);
|
||||||
expect($onChangesControllerSpyA.calls.argsFor(0)[0]).toEqual({
|
expect($onChangesControllerSpyA.calls.argsFor(0)[0]).toEqual({
|
||||||
valA: jasmine.objectContaining({currentValue: 'new value'})
|
valA: jasmine.objectContaining({currentValue: 'new value'})
|
||||||
});
|
});
|
||||||
|
|
||||||
expect($onChangesControllerSpyB).not.toHaveBeenCalled();
|
expect($onChangesControllerSpyB).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect($onChangesScopeSpy.calls.count()).toBe(1);
|
expect($onChangesScopeSpy.calls.count()).toBe(1);
|
||||||
expect($onChangesScopeSpy.calls.argsFor(0)[0]).toEqual({
|
expect($onChangesScopeSpy.calls.argsFor(0)[0]).toEqual({
|
||||||
valB: jasmine.objectContaining({currentValue: 'new value'})
|
valB: jasmine.objectContaining({currentValue: 'new value'})
|
||||||
});
|
});
|
||||||
|
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fixmeIvy(
|
it('should call `$onDestroy()` on controller', fakeAsync(() => {
|
||||||
'FW-843: destroy hooks are not registered on upgraded ng1 components contained in ng2 component templates under ivy')
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
.it('should call `$onDestroy()` on controller', fakeAsync(() => {
|
const $onDestroySpyA = jasmine.createSpy('$onDestroyA');
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const $onDestroySpyB = jasmine.createSpy('$onDestroyB');
|
||||||
const $onDestroySpyA = jasmine.createSpy('$onDestroyA');
|
let ng2ComponentInstance: Ng2Component;
|
||||||
const $onDestroySpyB = jasmine.createSpy('$onDestroyB');
|
|
||||||
let ng2ComponentInstance: Ng2Component;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ng2',
|
selector: 'ng2',
|
||||||
template: `
|
template: `
|
||||||
<div *ngIf="!ng2Destroy">
|
<div *ngIf="!ng2Destroy">
|
||||||
<ng1-a></ng1-a> | <ng1-b></ng1-b>
|
<ng1-a></ng1-a> | <ng1-b></ng1-b>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class Ng2Component {
|
class Ng2Component {
|
||||||
ng2Destroy: boolean = false;
|
ng2Destroy: boolean = false;
|
||||||
constructor() { ng2ComponentInstance = this; }
|
constructor() { ng2ComponentInstance = this; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
|
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
|
||||||
// `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be
|
// `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be
|
||||||
// on
|
// on
|
||||||
// the queue at the end of the test, causing it to fail.
|
// the queue at the end of the test, causing it to fail.
|
||||||
// Mocking animations (via `ngAnimateMock`) avoids the issue.
|
// Mocking animations (via `ngAnimateMock`) avoids the issue.
|
||||||
angular.module('ng1', ['ngAnimateMock'])
|
angular.module('ng1', ['ngAnimateMock'])
|
||||||
.directive('ng1A', () => ({
|
.directive('ng1A', () => ({
|
||||||
template: '',
|
template: '',
|
||||||
scope: {},
|
scope: {},
|
||||||
bindToController: true,
|
bindToController: true,
|
||||||
controllerAs: '$ctrl',
|
controllerAs: '$ctrl',
|
||||||
controller: class {$onDestroy() { $onDestroySpyA(); }}
|
controller: class {$onDestroy() { $onDestroySpyA(); }}
|
||||||
}))
|
}))
|
||||||
.directive(
|
.directive('ng1B', () => ({
|
||||||
'ng1B', () => ({
|
template: '',
|
||||||
template: '',
|
scope: {},
|
||||||
scope: {},
|
bindToController: false,
|
||||||
bindToController: false,
|
controllerAs: '$ctrl',
|
||||||
controllerAs: '$ctrl',
|
controller: function() { this.$onDestroy = $onDestroySpyB; }
|
||||||
controller: function() { this.$onDestroy = $onDestroySpyB; }
|
}))
|
||||||
}))
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'),
|
adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'),
|
||||||
Ng2Component
|
Ng2Component
|
||||||
],
|
],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
})
|
||||||
class Ng2Module {
|
class Ng2Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
const element = html(`<div ng-if="!ng1Destroy"><ng2></ng2></div>`);
|
const element = html(`<div ng-if="!ng1Destroy"><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
const $rootScope = ref.ng1RootScope as any;
|
const $rootScope = ref.ng1RootScope as any;
|
||||||
|
|
||||||
$rootScope.ng1Destroy = false;
|
$rootScope.ng1Destroy = false;
|
||||||
tick();
|
tick();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect($onDestroySpyA).not.toHaveBeenCalled();
|
expect($onDestroySpyA).not.toHaveBeenCalled();
|
||||||
expect($onDestroySpyB).not.toHaveBeenCalled();
|
expect($onDestroySpyB).not.toHaveBeenCalled();
|
||||||
|
|
||||||
$rootScope.ng1Destroy = true;
|
$rootScope.ng1Destroy = true;
|
||||||
tick();
|
tick();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect($onDestroySpyA).toHaveBeenCalled();
|
expect($onDestroySpyA).toHaveBeenCalled();
|
||||||
expect($onDestroySpyB).toHaveBeenCalled();
|
expect($onDestroySpyB).toHaveBeenCalled();
|
||||||
|
|
||||||
$onDestroySpyA.calls.reset();
|
$onDestroySpyA.calls.reset();
|
||||||
$onDestroySpyB.calls.reset();
|
$onDestroySpyB.calls.reset();
|
||||||
|
|
||||||
$rootScope.ng1Destroy = false;
|
$rootScope.ng1Destroy = false;
|
||||||
tick();
|
tick();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect($onDestroySpyA).not.toHaveBeenCalled();
|
expect($onDestroySpyA).not.toHaveBeenCalled();
|
||||||
expect($onDestroySpyB).not.toHaveBeenCalled();
|
expect($onDestroySpyB).not.toHaveBeenCalled();
|
||||||
|
|
||||||
ng2ComponentInstance.ng2Destroy = true;
|
ng2ComponentInstance.ng2Destroy = true;
|
||||||
tick();
|
tick();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect($onDestroySpyA).toHaveBeenCalled();
|
expect($onDestroySpyA).toHaveBeenCalled();
|
||||||
expect($onDestroySpyB).toHaveBeenCalled();
|
expect($onDestroySpyB).toHaveBeenCalled();
|
||||||
|
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not call `$onDestroy()` on scope', fakeAsync(() => {
|
it('should not call `$onDestroy()` on scope', fakeAsync(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
@ -3053,40 +3048,37 @@ withEachNg1Version(() => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy(
|
it('should bind input properties (<) of components', async(() => {
|
||||||
'FW-844: Directive input bindings cannot be assigned after the `@Directive` decorator has been compiled')
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
.it('should bind input properties (<) of components', async(() => {
|
const ng1Module = angular.module('ng1', []);
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
|
||||||
const ng1Module = angular.module('ng1', []);
|
|
||||||
|
|
||||||
const ng1 = {
|
const ng1 = {
|
||||||
bindings: {personProfile: '<'},
|
bindings: {personProfile: '<'},
|
||||||
template:
|
template: 'Hello {{$ctrl.personProfile.firstName}} {{$ctrl.personProfile.lastName}}',
|
||||||
'Hello {{$ctrl.personProfile.firstName}} {{$ctrl.personProfile.lastName}}',
|
controller: class {}
|
||||||
controller: class {}
|
};
|
||||||
};
|
ng1Module.component('ng1', ng1);
|
||||||
ng1Module.component('ng1', ng1);
|
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<ng1 [personProfile]="goku"></ng1>'})
|
@Component({selector: 'ng2', template: '<ng1 [personProfile]="goku"></ng1>'})
|
||||||
class Ng2 {
|
class Ng2 {
|
||||||
goku = {firstName: 'GOKU', lastName: 'SAN'};
|
goku = {firstName: 'GOKU', lastName: 'SAN'};
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
})
|
||||||
class Ng2Module {
|
class Ng2Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
const element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
expect(multiTrim(document.body.textContent)).toEqual(`Hello GOKU SAN`);
|
expect(multiTrim(document.body.textContent)).toEqual(`Hello GOKU SAN`);
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support ng2 > ng1 > ng2', async(() => {
|
it('should support ng2 > ng1 > ng2', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
@ -3968,6 +3968,7 @@ withEachNg1Version(() => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// fixmeIvy('FW-724: upgraded ng1 components are not being rendered')
|
||||||
it('should support ng2 > ng1 > ng2 (with inputs/outputs)', fakeAsync(() => {
|
it('should support ng2 > ng1 > ng2 (with inputs/outputs)', fakeAsync(() => {
|
||||||
let ng2ComponentAInstance: Ng2ComponentA;
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
let ng2ComponentBInstance: Ng2ComponentB;
|
let ng2ComponentBInstance: Ng2ComponentB;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user