diff --git a/examples/angular/row-selection/src/app/app.component.ts b/examples/angular/row-selection/src/app/app.component.ts index 8711fd3959..5e2e103b4a 100644 --- a/examples/angular/row-selection/src/app/app.component.ts +++ b/examples/angular/row-selection/src/app/app.component.ts @@ -9,7 +9,6 @@ import { import { ColumnDef, createAngularTable, - FlexRenderComponent, FlexRenderDirective, getCoreRowModel, getFilteredRowModel, @@ -18,7 +17,6 @@ import { } from '@tanstack/angular-table' import { FilterComponent } from './filter' import { makeData, type Person } from './makeData' -import { FormsModule } from '@angular/forms' import { TableHeadSelectionComponent, TableRowSelectionComponent, @@ -27,7 +25,7 @@ import { @Component({ selector: 'app-root', standalone: true, - imports: [FilterComponent, FlexRenderDirective, FormsModule], + imports: [FilterComponent, FlexRenderDirective], templateUrl: './app.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) @@ -42,12 +40,8 @@ export class AppComponent { readonly columns: ColumnDef[] = [ { id: 'select', - header: () => { - return new FlexRenderComponent(TableHeadSelectionComponent) - }, - cell: () => { - return new FlexRenderComponent(TableRowSelectionComponent) - }, + header: () => TableHeadSelectionComponent, + cell: () => TableRowSelectionComponent, }, { header: 'Name', diff --git a/examples/angular/row-selection/src/app/selection-column.component.ts b/examples/angular/row-selection/src/app/selection-column.component.ts index b4f3e1c008..e10015a149 100644 --- a/examples/angular/row-selection/src/app/selection-column.component.ts +++ b/examples/angular/row-selection/src/app/selection-column.component.ts @@ -1,17 +1,13 @@ -import { - type CellContext, - type HeaderContext, - injectFlexRenderContext, -} from '@tanstack/angular-table' -import { ChangeDetectionStrategy, Component } from '@angular/core' +import { ChangeDetectionStrategy, Component, input } from '@angular/core' +import { Row, Table } from '@tanstack/angular-table' @Component({ template: ` `, host: { @@ -21,15 +17,23 @@ import { ChangeDetectionStrategy, Component } from '@angular/core' changeDetection: ChangeDetectionStrategy.OnPush, }) export class TableHeadSelectionComponent { - context = injectFlexRenderContext>() + // Your component should also reflect the fields you use as props in flexRenderer directive. + // Define the fields as input you want to use in your component + // ie. In this case, you are passing HeaderContext object as props in flexRenderer directive. + // You can define and use the table field, which is defined in HeaderContext. + // Please take note that only signal based input is supported. + + //column = input.required>(); + //header = input.required>(); + table = input.required>() } @Component({ template: ` `, host: { @@ -39,5 +43,5 @@ export class TableHeadSelectionComponent { changeDetection: ChangeDetectionStrategy.OnPush, }) export class TableRowSelectionComponent { - context = injectFlexRenderContext>() + row = input.required>() } diff --git a/packages/angular-table/src/flex-render.ts b/packages/angular-table/src/flex-render.ts index 46242761d9..9f44547744 100644 --- a/packages/angular-table/src/flex-render.ts +++ b/packages/angular-table/src/flex-render.ts @@ -1,23 +1,19 @@ import { - ChangeDetectorRef, ComponentRef, Directive, - type DoCheck, EmbeddedViewRef, - inject, - InjectionToken, Injector, - Input, - type OnInit, TemplateRef, - type Type, + Type, ViewContainerRef, + inject, + input, } from '@angular/core' type FlexRenderContent> = | string | number - | FlexRenderComponent + | Type | TemplateRef<{ $implicit: TProps }> | null @@ -25,80 +21,53 @@ type FlexRenderContent> = selector: '[flexRender]', standalone: true, }) -export class FlexRenderDirective> - implements OnInit, DoCheck -{ - @Input({ required: true, alias: 'flexRender' }) - content: - | number - | string - | ((props: TProps) => FlexRenderContent) - | undefined = undefined - - @Input({ required: true, alias: 'flexRenderProps' }) - props: TProps = {} as TProps +export class FlexRenderDirective> { + // set the type to unknown as input signal is not able to recognize the types correctly + // which causes build error + content = input.required({ alias: 'flexRender' }) - @Input({ required: false, alias: 'flexRenderInjector' }) - injector: Injector = inject(Injector) + props = input({} as TProps, { alias: 'flexRenderProps' }) - constructor( - private viewContainerRef: ViewContainerRef, - private templateRef: TemplateRef - ) {} - - ref?: ComponentRef | EmbeddedViewRef | null = null + private readonly injector = inject(Injector) + private readonly viewContainerRef = inject(ViewContainerRef) + private readonly templateRef = inject(TemplateRef) ngOnInit(): void { - this.ref = this.render() - } - - ngDoCheck() { - if (this.ref instanceof ComponentRef) { - this.ref.injector.get(ChangeDetectorRef).markForCheck() - } else if (this.ref instanceof EmbeddedViewRef) { - this.ref.markForCheck() - } + this.render() } render() { this.viewContainerRef.clear() - const { content, props } = this - if (!this.content) { + const content = this.content() + if (!content) { return null } - if (typeof content === 'string' || typeof content === 'number') { - return this.renderStringContent() - } if (typeof content === 'function') { - return this.renderContent(content(props)) + return this.renderContent(content(this.props())) } - return null + return this.renderStringContent(content as FlexRenderContent) } private renderContent(content: FlexRenderContent) { - if (typeof content === 'string' || typeof content === 'number') { - return this.renderStringContent() - } if (content instanceof TemplateRef) { return this.viewContainerRef.createEmbeddedView( content, this.getTemplateRefContext() ) - } else if (content instanceof FlexRenderComponent) { + } else if (content instanceof Type) { return this.renderComponent(content) + } else if (content) { + return this.renderStringContent(content) } else { return null } } - private renderStringContent(): EmbeddedViewRef { - const context = () => { - return typeof this.content === 'string' || - typeof this.content === 'number' - ? this.content - : this.content?.(this.props) - } + private renderStringContent( + content: FlexRenderContent + ): EmbeddedViewRef { + const context = () => content return this.viewContainerRef.createEmbeddedView(this.templateRef, { get $implicit() { return context() @@ -106,35 +75,22 @@ export class FlexRenderDirective> }) } - private renderComponent( - flexRenderComponent: FlexRenderComponent - ): ComponentRef { - const { component, inputs, injector } = flexRenderComponent - - const getContext = () => this.props - - const proxy = new Proxy(this.props, { - get: (_, key) => getContext()?.[key as keyof typeof _], - }) - - const componentInjector = Injector.create({ - parent: injector ?? this.injector, - providers: [{ provide: FlexRenderComponentProps, useValue: proxy }], - }) - + private renderComponent(component: Type): ComponentRef { const componentRef = this.viewContainerRef.createComponent(component, { - injector: componentInjector, + injector: this.injector, }) - for (const prop in inputs) { + const props = this.props() + for (const prop in props) { + // Only signal based input can be added here if (componentRef.instance?.hasOwnProperty(prop)) { - componentRef.setInput(prop, inputs[prop]) + componentRef.setInput(prop, props[prop]) } } return componentRef } private getTemplateRefContext() { - const getContext = () => this.props + const getContext = () => this.props() return { get $implicit() { return getContext() @@ -142,19 +98,3 @@ export class FlexRenderDirective> } } } - -export class FlexRenderComponent> { - constructor( - readonly component: Type, - readonly inputs: T = {} as T, - readonly injector?: Injector - ) {} -} - -const FlexRenderComponentProps = new InjectionToken>( - '[@tanstack/angular-table] Flex render component context props' -) - -export function injectFlexRenderContext>(): T { - return inject(FlexRenderComponentProps) -} diff --git a/packages/angular-table/src/index.ts b/packages/angular-table/src/index.ts index b702caeb74..3870cda464 100644 --- a/packages/angular-table/src/index.ts +++ b/packages/angular-table/src/index.ts @@ -12,11 +12,7 @@ import { proxifyTable } from './proxy' export * from '@tanstack/table-core' -export { - FlexRenderComponent, - FlexRenderDirective, - injectFlexRenderContext, -} from './flex-render' +export { FlexRenderDirective } from './flex-render' export function createAngularTable( options: () => TableOptions