|
1 | | -import { ApplicationRef, ChangeDetectorRef, ComponentFactory, ComponentRef, Injector, OnChanges, QueryList, Type, ViewContainerRef, reflectComponentType } from '@angular/core'; |
2 | | -import { NgElement } from '@angular/elements'; |
3 | | -import { fromEvent } from 'rxjs'; |
4 | | -import { takeUntil } from 'rxjs/operators'; |
| 1 | +import { ApplicationRef, ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, QueryList, Type, ViewContainerRef, reflectComponentType } from '@angular/core'; |
| 2 | +import { NgElement, NgElementStrategyEvent } from '@angular/elements'; |
| 3 | +import { fromEvent, Observable } from 'rxjs'; |
| 4 | +import { map, takeUntil } from 'rxjs/operators'; |
5 | 5 | import { ComponentConfig, ContentQueryMeta } from './component-config'; |
6 | 6 |
|
7 | 7 | import { ComponentNgElementStrategy, ComponentNgElementStrategyFactory, extractProjectableNodes, isFunction } from './ng-element-strategy'; |
@@ -388,6 +388,65 @@ class IgxCustomNgElementStrategy extends ComponentNgElementStrategy { |
388 | 388 | super.disconnect(); |
389 | 389 | } |
390 | 390 | } |
| 391 | + |
| 392 | + //#region Handle event args that return reference to components, since they return angular ref and not custom elements. |
| 393 | + /** Sets up listeners for the component's outputs so that the events stream emits the events. */ |
| 394 | + protected override initializeOutputs(componentRef: ComponentRef<any>): void { |
| 395 | + const eventEmitters: Observable<NgElementStrategyEvent>[] = this._componentFactory.outputs.map( |
| 396 | + ({ propName, templateName }) => { |
| 397 | + const emitter: EventEmitter<any> = componentRef.instance[propName]; |
| 398 | + return emitter.pipe(map((value: any) => ({ name: templateName, value: this.patchOutputComponents(value) }))); |
| 399 | + }, |
| 400 | + ); |
| 401 | + |
| 402 | + (this as any).eventEmitters.next(eventEmitters); |
| 403 | + } |
| 404 | + |
| 405 | + protected patchOutputComponents(eventArgs: any) { |
| 406 | + let componentConfig: ComponentConfig = this.findConfig(eventArgs); |
| 407 | + if (componentConfig?.templateProps) { |
| 408 | + // The event return directly reference to a component, so directly return a proxy of it. |
| 409 | + eventArgs = this.createElementsComponentProxy(eventArgs, componentConfig); |
| 410 | + } else if (!componentConfig) { |
| 411 | + // Check if the event args have property with component reference and replace it with proxy as well. |
| 412 | + for (const [key, value] of Object.entries(eventArgs)) { |
| 413 | + componentConfig = this.findConfig(value); |
| 414 | + if (componentConfig?.templateProps) { |
| 415 | + eventArgs[key] = this.createElementsComponentProxy(value, componentConfig); |
| 416 | + } |
| 417 | + } |
| 418 | + } |
| 419 | + return eventArgs; |
| 420 | + } |
| 421 | + |
| 422 | + /** Find config for a component, assuming the provided object is correct. Otherwise will return undefined. */ |
| 423 | + protected findConfig(component: any) { |
| 424 | + // Make sure we match the correct type(first half) and not the one it inherits(second half of check). |
| 425 | + return this.config.find((info: ComponentConfig) => component instanceof info.component && !(component.__proto__ instanceof info.component)); |
| 426 | + } |
| 427 | + |
| 428 | + /** Create proxy for a component that handles setting template props, making sure it provides correct TemplateRef and not Lit template */ |
| 429 | + protected createElementsComponentProxy(component: any, config: ComponentConfig) { |
| 430 | + const parentThis = this; |
| 431 | + return new Proxy(component, { |
| 432 | + set(target: any, prop: string, newValue: any) { |
| 433 | + // For now handle only template props |
| 434 | + if (config.templateProps.includes(prop)) { |
| 435 | + const oldRef = target[prop]; |
| 436 | + const oldValue = oldRef && parentThis.templateWrapper.getTemplateFunction(oldRef); |
| 437 | + if (oldValue === newValue) { |
| 438 | + newValue = oldRef; |
| 439 | + } else { |
| 440 | + newValue = parentThis.templateWrapper.addTemplate(newValue); |
| 441 | + } |
| 442 | + } |
| 443 | + target[prop] = newValue; |
| 444 | + |
| 445 | + return true; |
| 446 | + } |
| 447 | + }); |
| 448 | + } |
| 449 | + //#endregion |
391 | 450 | } |
392 | 451 |
|
393 | 452 | /** |
|
0 commit comments