Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 16 additions & 19 deletions packages/angular-table/src/flex-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import {
Directive,
EmbeddedViewRef,
Inject,
inject,
InjectionToken,
Injector,
Input,
isSignal,
type OnChanges,
type SimpleChanges,
TemplateRef,
Type,
ViewContainerRef,
inject,
isSignal,
type DoCheck,
type OnInit,
} from '@angular/core'

export type FlexRenderContent<TProps extends NonNullable<unknown>> =
Expand All @@ -30,13 +30,14 @@ export type FlexRenderContent<TProps extends NonNullable<unknown>> =
standalone: true,
})
export class FlexRenderDirective<TProps extends NonNullable<unknown>>
implements OnInit, DoCheck
implements OnChanges
{
@Input({ required: true, alias: 'flexRender' })
content:
| number
| string
| ((props: TProps) => FlexRenderContent<TProps>)
| null
| undefined = undefined

@Input({ required: true, alias: 'flexRenderProps' })
Expand All @@ -54,32 +55,28 @@ export class FlexRenderDirective<TProps extends NonNullable<unknown>>

ref?: ComponentRef<unknown> | EmbeddedViewRef<unknown> | null = null

ngOnInit(): void {
this.ref = this.render()
}

ngDoCheck() {
ngOnChanges(changes: SimpleChanges) {
if (this.ref instanceof ComponentRef) {
this.ref.injector.get(ChangeDetectorRef).markForCheck()
} else if (this.ref instanceof EmbeddedViewRef) {
this.ref.markForCheck()
}
if (!changes['content']) {
return
}
this.render()
}

render() {
this.viewContainerRef.clear()
const { content, props } = this
if (!this.content) {
return null
}

if (typeof content === 'string' || typeof content === 'number') {
return this.renderStringContent()
if (content === null || content === undefined) {
this.ref = null
return
}
if (typeof content === 'function') {
return this.renderContent(content(props))
} else {
return this.renderContent(content)
}
return null
}

private renderContent(content: FlexRenderContent<TProps>) {
Expand Down
29 changes: 18 additions & 11 deletions packages/angular-table/tests/flex-render.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, ViewChild, input, type TemplateRef } from '@angular/core'
import { TestBed, type ComponentFixture } from '@angular/core/testing'
import { createColumnHelper } from '@tanstack/table-core'
import { skip } from 'node:test'
import { describe, expect, test } from 'vitest'
import {
FlexRenderComponent,
Expand All @@ -24,6 +23,20 @@ describe('FlexRenderDirective', () => {
test('should render primitives', async () => {
const fixture = TestBed.createComponent(TestRenderComponent)

// Null
setFixtureSignalInputs(fixture, {
content: () => null,
context: {},
})
expect((fixture.nativeElement as HTMLElement).matches(':empty')).toBe(true)

// Undefined
setFixtureSignalInputs(fixture, {
content: () => undefined,
context: {},
})
expect((fixture.nativeElement as HTMLElement).matches(':empty')).toBe(true)

// String
setFixtureSignalInputs(fixture, {
content: 'My value',
Expand All @@ -45,19 +58,12 @@ describe('FlexRenderDirective', () => {
})
expectPrimitiveValueIs(fixture, 'My value 2')

// Null
// Set again to null to be sure content has been destroyed
setFixtureSignalInputs(fixture, {
content: () => null,
context: {},
})
expectPrimitiveValueIs(fixture, '')

// Undefined
setFixtureSignalInputs(fixture, {
content: () => undefined,
context: {},
})
expectPrimitiveValueIs(fixture, '')
expect((fixture.nativeElement as HTMLElement).matches(':empty')).toBe(true)
})

test('should render TemplateRef', () => {
Expand Down Expand Up @@ -118,7 +124,7 @@ describe('FlexRenderDirective', () => {

// Skip for now, test framework (using ComponentRef.setInput) cannot recognize signal inputs
// as component inputs
skip('should render custom components', () => {
test.skip('should render custom components', () => {
@Component({
template: `{{ row().property }}`,
standalone: true,
Expand Down Expand Up @@ -172,6 +178,7 @@ function expectPrimitiveValueIs(
fixture: ComponentFixture<unknown>,
value: unknown
) {
expect(fixture.nativeElement.matches(':empty')).toBe(false)
const span = fixture.nativeElement.querySelector('span')
expect(span).toBeDefined()
expect(span.innerHTML).toEqual(value)
Expand Down