Skip to content

Commit f5e1faa

Browse files
Zuckjetalxhub
authored andcommitted
fix(core): make subclass inherit developer-defined data (#35105)
PR Close #35105
1 parent 5bec534 commit f5e1faa

File tree

2 files changed

+170
-3
lines changed

2 files changed

+170
-3
lines changed

packages/core/src/render3/features/inherit_definition_feature.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
*/
88

99
import {Type, Writable} from '../../interface/type';
10-
import {assertEqual} from '../../util/assert';
1110
import {fillProperties} from '../../util/property';
1211
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
1312
import {ComponentDef, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, HostBindingsFunction, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
14-
import {AttributeMarker, TAttributes} from '../interfaces/node';
13+
import {TAttributes} from '../interfaces/node';
1514
import {isComponentDef} from '../interfaces/type_checks';
1615
import {mergeHostAttrs} from '../util/attrs_utils';
1716

@@ -71,6 +70,15 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef<any>| Comp
7170
fillProperties(definition.declaredInputs, superDef.declaredInputs);
7271
fillProperties(definition.outputs, superDef.outputs);
7372

73+
// Merge animations metadata.
74+
// If `superDef` is a Component, the `data` field is present (defaults to an empty object).
75+
if (isComponentDef(superDef) && superDef.data.animation) {
76+
// If super def is a Component, the `definition` is also a Component, since Directives can
77+
// not inherit Components (we throw an error above and cannot reach this code).
78+
const defData = (definition as ComponentDef<any>).data;
79+
defData.animation = (defData.animation || []).concat(superDef.data.animation);
80+
}
81+
7482
// Inherit hooks
7583
// Assume super class inheritance feature has already run.
7684
writeableDef.afterContentChecked =
@@ -179,4 +187,4 @@ function inheritHostBindings(
179187
} else {
180188
definition.hostBindings = superHostBindings;
181189
}
182-
}
190+
}

packages/core/test/acceptance/inherit_definition_feature_spec.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {state, style, trigger} from '@angular/animations';
910
import {Component, ContentChildren, Directive, EventEmitter, HostBinding, HostListener, Input, OnChanges, Output, QueryList, ViewChildren} from '@angular/core';
1011
import {ivyEnabled} from '@angular/core/src/ivy_switch';
1112
import {getDirectiveDef} from '@angular/core/src/render3/definition';
1213
import {TestBed} from '@angular/core/testing';
1314
import {By} from '@angular/platform-browser';
15+
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
1416
import {onlyInIvy} from '@angular/private/testing';
1517

1618
describe('inheritance', () => {
@@ -4132,6 +4134,99 @@ describe('inheritance', () => {
41324134
});
41334135
});
41344136

4137+
describe('animations', () => {
4138+
onlyInIvy('View Engine does not inherit `host` metadata from superclass')
4139+
.it('should work with inherited host bindings and animations', () => {
4140+
@Component({
4141+
selector: 'super-comp',
4142+
template: '<div>super-comp</div>',
4143+
host: {
4144+
'[@animation]': 'colorExp',
4145+
},
4146+
animations: [
4147+
trigger('animation', [state('color', style({color: 'red'}))]),
4148+
],
4149+
})
4150+
class SuperComponent {
4151+
colorExp = 'color';
4152+
}
4153+
4154+
@Component({
4155+
selector: 'my-comp',
4156+
template: `<div>my-comp</div>`,
4157+
})
4158+
class MyComponent extends SuperComponent {
4159+
}
4160+
4161+
@Component({
4162+
template: '<my-comp>app</my-comp>',
4163+
})
4164+
class App {
4165+
}
4166+
4167+
TestBed.configureTestingModule({
4168+
declarations: [App, MyComponent, SuperComponent],
4169+
imports: [NoopAnimationsModule],
4170+
});
4171+
const fixture = TestBed.createComponent(App);
4172+
fixture.detectChanges();
4173+
const queryResult = fixture.debugElement.query(By.css('my-comp'));
4174+
4175+
expect(queryResult.nativeElement.style.color).toBe('red');
4176+
});
4177+
4178+
onlyInIvy('View Engine does not inherit `host` metadata from superclass')
4179+
.it('should compose animations (from super class)', () => {
4180+
@Component({
4181+
selector: 'super-comp',
4182+
template: '...',
4183+
animations: [
4184+
trigger('animation1', [state('color', style({color: 'red'}))]),
4185+
trigger('animation2', [state('opacity', style({opacity: '0.5'}))]),
4186+
],
4187+
})
4188+
class SuperComponent {
4189+
}
4190+
4191+
@Component({
4192+
selector: 'my-comp',
4193+
template: '<div>my-comp</div>',
4194+
host: {
4195+
'[@animation1]': 'colorExp',
4196+
'[@animation2]': 'opacityExp',
4197+
'[@animation3]': 'bgExp',
4198+
},
4199+
animations: [
4200+
trigger('animation1', [state('color', style({color: 'blue'}))]),
4201+
trigger('animation3', [state('bg', style({backgroundColor: 'green'}))]),
4202+
],
4203+
})
4204+
class MyComponent extends SuperComponent {
4205+
colorExp = 'color';
4206+
opacityExp = 'opacity';
4207+
bgExp = 'bg';
4208+
}
4209+
4210+
@Component({
4211+
template: '<my-comp>app</my-comp>',
4212+
})
4213+
class App {
4214+
}
4215+
4216+
TestBed.configureTestingModule({
4217+
declarations: [App, MyComponent, SuperComponent],
4218+
imports: [NoopAnimationsModule],
4219+
});
4220+
const fixture = TestBed.createComponent(App);
4221+
fixture.detectChanges();
4222+
const queryResult = fixture.debugElement.query(By.css('my-comp'));
4223+
4224+
expect(queryResult.nativeElement.style.color).toBe('blue');
4225+
expect(queryResult.nativeElement.style.opacity).toBe('0.5');
4226+
expect(queryResult.nativeElement.style.backgroundColor).toBe('green');
4227+
});
4228+
});
4229+
41354230
describe('host bindings (style related)', () => {
41364231
// TODO: sub and super HostBinding same property but different bindings
41374232
// TODO: sub and super HostBinding same binding on two different properties
@@ -4819,6 +4914,70 @@ describe('inheritance', () => {
48194914
});
48204915
});
48214916

4917+
describe('animations', () => {
4918+
onlyInIvy('View Engine does not inherit `host` metadata from superclass')
4919+
.it('should compose animations across multiple inheritance levels', () => {
4920+
@Component({
4921+
selector: 'super-comp',
4922+
template: '...',
4923+
host: {
4924+
'[@animation1]': 'colorExp',
4925+
'[@animation2]': 'opacityExp',
4926+
},
4927+
animations: [
4928+
trigger('animation1', [state('color', style({color: 'red'}))]),
4929+
trigger('animation2', [state('opacity', style({opacity: '0.5'}))]),
4930+
],
4931+
})
4932+
class SuperComponent {
4933+
colorExp = 'color';
4934+
opacityExp = 'opacity';
4935+
}
4936+
4937+
@Component({
4938+
selector: 'intermediate-comp',
4939+
template: '...',
4940+
})
4941+
class IntermediateComponent extends SuperComponent {
4942+
}
4943+
4944+
@Component({
4945+
selector: 'my-comp',
4946+
template: '<div>my-comp</div>',
4947+
host: {
4948+
'[@animation1]': 'colorExp',
4949+
'[@animation3]': 'bgExp',
4950+
},
4951+
animations: [
4952+
trigger('animation1', [state('color', style({color: 'blue'}))]),
4953+
trigger('animation3', [state('bg', style({backgroundColor: 'green'}))]),
4954+
],
4955+
})
4956+
class MyComponent extends IntermediateComponent {
4957+
colorExp = 'color';
4958+
opacityExp = 'opacity';
4959+
bgExp = 'bg';
4960+
}
4961+
4962+
@Component({
4963+
template: '<my-comp>app</my-comp>',
4964+
})
4965+
class App {
4966+
}
4967+
4968+
TestBed.configureTestingModule({
4969+
declarations: [App, MyComponent, IntermediateComponent, SuperComponent],
4970+
imports: [NoopAnimationsModule],
4971+
});
4972+
const fixture = TestBed.createComponent(App);
4973+
fixture.detectChanges();
4974+
const queryResult = fixture.debugElement.query(By.css('my-comp'));
4975+
4976+
expect(queryResult.nativeElement.style.color).toBe('blue');
4977+
expect(queryResult.nativeElement.style.opacity).toBe('0.5');
4978+
expect(queryResult.nativeElement.style.backgroundColor).toBe('green');
4979+
});
4980+
});
48224981
describe('host bindings (style related)', () => {
48234982
// TODO: sub and super HostBinding same property but different bindings
48244983
// TODO: sub and super HostBinding same binding on two different properties

0 commit comments

Comments
 (0)