Asymmetrik/ngx-starter

View on GitHub
src/app/common/table/columns/asy-abstract-column.component.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { CdkCellDef, CdkColumnDef, CdkHeaderCellDef, CdkTable } from '@angular/cdk/table';
import {
    Directive,
    Input,
    OnDestroy,
    OnInit,
    ViewChild,
    booleanAttribute,
    inject,
    input
} from '@angular/core';

@Directive({ standalone: true })
export abstract class AsyAbstractColumnComponent<T> implements OnDestroy, OnInit {
    /** Column name that should be used to reference this column. */
    @Input()
    get name(): string {
        return this._name;
    }
    set name(name: string) {
        this._name = name;

        // With Ivy, inputs can be initialized before static query results are
        // available. In that case, we defer the synchronization until "ngOnInit" fires.
        this._syncColumnDefName();
    }
    _name: string;

    /**
     * Whether this column should be sticky positioned on the front of the row.
     */
    readonly sticky = input(false, { transform: booleanAttribute });

    /**
     * Whether this column should be sticky positioned on the end of the row.
     */
    readonly stickyEnd = input(false, { transform: booleanAttribute });

    /** @docs-private */
    @ViewChild(CdkColumnDef, { static: true }) columnDef: CdkColumnDef;

    /**
     * The column cell is provided to the column during `ngOnInit` with a static query.
     * Normally, this will be retrieved by the column using `ContentChild`, but that assumes the
     * column definition was provided in the same view as the table, which is not the case with this
     * component.
     * @docs-private
     */
    @ViewChild(CdkCellDef, { static: true }) cell: CdkCellDef;

    /**
     * The column headerCell is provided to the column during `ngOnInit` with a static query.
     * Normally, this will be retrieved by the column using `ContentChild`, but that assumes the
     * column definition was provided in the same view as the table, which is not the case with this
     * component.
     * @docs-private
     */
    @ViewChild(CdkHeaderCellDef, { static: true }) headerCell: CdkHeaderCellDef;

    // `AsyAbstractColumn` is always requiring a table, but we just assert it manually
    // for better error reporting.
    protected _table: CdkTable<T> = inject(CdkTable, { optional: true }) as CdkTable<T>;

    ngOnInit(): void {
        if (!this._table) {
            throw Error('column could not find a parent table for registration.');
        }
        this._syncColumnDefName();

        // Provide the cell and headerCell directly to the table with the static `ViewChild` query,
        // since the columnDef will not pick up its content by the time the table finishes checking
        // its content and initializing the rows.
        this.columnDef.cell = this.cell;
        this.columnDef.headerCell = this.headerCell;
        this._table.addColumnDef(this.columnDef);
    }

    ngOnDestroy() {
        this._table?.removeColumnDef(this.columnDef);
    }

    /** Synchronizes the column definition name with the text column name. */
    private _syncColumnDefName() {
        if (this.columnDef) {
            this.columnDef.name = this.name;
        }
    }
}