grid-js / gridjs

Advanced table plugin
https://gridjs.io
MIT License
4.41k stars 241 forks source link

Example for Angular formatters #465

Closed ubergeoff closed 3 years ago

ubergeoff commented 3 years ago

Proposal and/or example for future Angular GridJS custom formatter columns Ability to add Custom Angular components as "formatter"

Please see my proposed solution/example

export class GridDemoComponent implements OnInit {
    columns: OneDArray<any> = [
        {
            name: 'CheckBox',
            sort: false,
            width: '5px',
            formatter: (cellData) => {
                return createDivContainer((div) => {
                    div.appendChild(this.createCheckBox(cellData).location.nativeElement);
                });
            }
        },
        'Name',
        'Email',
        'Phone Number',
        {
            name: 'Button',
            sort: false,
            width: '30px',
            formatter: (cellData) => {
                return createDivContainer((div) => {
                    div.appendChild(this.createButton(cellData).location.nativeElement);
                });
            }
        }
    ];

    data$: Observable<any[]>;
    private dataSubject = new BehaviorSubject<any[]>([]);

    constructor(
        private dialog: MatDialog,
        private componentFactory: ComponentFactoryResolver,
        private viewContainerRef: ViewContainerRef
    ) {}

    ngOnInit(): void {
        this.data$ = this.dataSubject.pipe(debounceTime(1000));

        this.dataSubject.next([
            [true, 'John', 'john@example.com', '(353) 01 222 3333', 22],
            [false, 'Mark', 'mark@gmail.com', '(01) 22 888 4444', 33]
        ]);
    }

    openModal(rowData) {
        this.dialog.open(DialogComponent, { data: rowData });
    }

    createComponent<T>(type: Type<T>): ComponentRef<T> {
        const componentFactory = this.componentFactory.resolveComponentFactory(type);
        return this.viewContainerRef.createComponent<T>(componentFactory);
    }

   // any custom Angular component
    createButton(cellData) {
        const button = this.createComponent<ActionButtonComponent>(ActionButtonComponent);
        button.instance.eventFunction = () => this.openModal(cellData);

        return button;
    }

    // Angular Material component
    createCheckBox(cellData) {
        const checkBox = this.createComponent<MatCheckbox>(MatCheckbox);
        checkBox.instance.checked = cellData;

        return checkBox;
    }
}

And the createDivContainer function:

import { h, createRef as gCreateRef } from 'gridjs';

export function createDivContainer(creatorFunction) {
    const ref = gCreateRef();
    const div = h('div', { ref: ref });
    setTimeout(() => {
        if (ref.current?.children.length === 0) {
            creatorFunction(ref.current);
        }
    }, 0);
    return div;
}

Would this be considered a good practice..?

Are there any further enhancement that can be applied to the above example..?

ubergeoff commented 3 years ago

DEMO here: https://www.flingo.co.za/grid/dashboard1

afshinm commented 3 years ago

Thanks for the question and your demo @ubergeoff -- your solution makes sense to me. I don't really have any suggestions to improve your existing solution.

afshinm commented 3 years ago

I think it's a good idea to add this to our examples on gridjs.io.

joeskeen commented 6 months ago

@afshinm we definitely need to add this to this section of the documentation https://gridjs.io/docs/integrations/angular/#can-i-use-angular-components-in-plugins-formatters-etc-not-yet

Currently it says the following, which is not true:

Can I use Angular components in plugins, formatters, etc? Not yet

I have constructed a StackBlitz that is a self-contained example of how to render an Angular component or template inside of a Grid.JS cell:

https://stackblitz.com/edit/stackblitz-starters-ng6gl4?file=package.json