Skip to content

Commit fe5c4e0

Browse files
alxhubAndrewKushnir
authored andcommitted
fix(elements): support output()-shaped outputs (#57535)
Previously Elements was assuming that every output was an RxJS `Subject` and supports `.pipe()`. This is not true for `output()`-based outputs which have `.subscribe()` but not `.pipe()`. This commit fixes such outputs by using a `new Observable` instead of `map` to forward outputs. PR Close #57535
1 parent 3896f86 commit fe5c4e0

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

packages/elements/src/component-factory-strategy.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import {
1818
ɵChangeDetectionScheduler as ChangeDetectionScheduler,
1919
ɵNotificationSource as NotificationSource,
2020
ɵViewRef as ViewRef,
21+
OutputRef,
2122
} from '@angular/core';
2223
import {merge, Observable, ReplaySubject} from 'rxjs';
23-
import {map, switchMap} from 'rxjs/operators';
24+
import {switchMap} from 'rxjs/operators';
2425

2526
import {
2627
NgElementStrategy,
@@ -219,8 +220,11 @@ export class ComponentNgElementStrategy implements NgElementStrategy {
219220
protected initializeOutputs(componentRef: ComponentRef<any>): void {
220221
const eventEmitters: Observable<NgElementStrategyEvent>[] = this.componentFactory.outputs.map(
221222
({propName, templateName}) => {
222-
const emitter: EventEmitter<any> = componentRef.instance[propName];
223-
return emitter.pipe(map((value) => ({name: templateName, value})));
223+
const emitter: EventEmitter<any> | OutputRef<any> = componentRef.instance[propName];
224+
return new Observable((observer) => {
225+
const sub = emitter.subscribe((value) => observer.next({name: templateName, value}));
226+
return () => sub.unsubscribe();
227+
});
224228
},
225229
);
226230

packages/elements/test/component-factory-strategy_spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
Input,
1717
NgZone,
1818
Output,
19+
OutputEmitterRef,
1920
SimpleChange,
2021
SimpleChanges,
2122
createComponent,
@@ -113,6 +114,18 @@ describe('ComponentFactoryNgElementStrategy', () => {
113114
]);
114115
});
115116

117+
it('should listen to output() emitters', () => {
118+
const events: NgElementStrategyEvent[] = [];
119+
strategy.events.subscribe((e) => events.push(e));
120+
121+
componentRef.instance.output3.emit('output-a');
122+
componentRef.instance.output3.emit('output-b');
123+
expect(events).toEqual([
124+
{name: 'templateOutput3', value: 'output-a'},
125+
{name: 'templateOutput3', value: 'output-b'},
126+
]);
127+
});
128+
116129
it('should initialize the component with initial values', () => {
117130
expect(strategy.getInputValue('fooFoo')).toBe('fooFoo-1');
118131
expect(componentRef.instance.fooFoo).toBe('fooFoo-1');
@@ -369,6 +382,7 @@ export class CdTrackerDir {
369382
export class TestComponent {
370383
@Output('templateOutput1') output1 = new Subject();
371384
@Output('templateOutput2') output2 = new Subject();
385+
@Output('templateOutput3') output3 = new OutputEmitterRef();
372386

373387
@Input() fooFoo: unknown;
374388
@Input({alias: 'my-bar-bar'}) barBar: unknown;

0 commit comments

Comments
 (0)