diff --git a/apps/demo/project.json b/apps/demo/project.json
index 7ee2240..7683b09 100644
--- a/apps/demo/project.json
+++ b/apps/demo/project.json
@@ -16,7 +16,7 @@
"polyfills": ["zone.js"],
"tsConfig": "apps/demo/tsconfig.app.json",
"assets": ["apps/demo/src/favicon.ico", "apps/demo/src/assets"],
- "styles": ["node_modules/gridjs/dist/theme/mermaid.min.css"],
+ "styles": ["apps/demo/src/styles.css"],
"scripts": []
},
"configurations": {
diff --git a/apps/demo/src/app/app.component.css b/apps/demo/src/app/app.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/apps/demo/src/app/app.component.html b/apps/demo/src/app/app.component.html
new file mode 100644
index 0000000..a57ab4e
--- /dev/null
+++ b/apps/demo/src/app/app.component.html
@@ -0,0 +1,2 @@
+
+
diff --git a/apps/demo/src/app/app.component.ts b/apps/demo/src/app/app.component.ts
index 8a4f449..394c181 100644
--- a/apps/demo/src/app/app.component.ts
+++ b/apps/demo/src/app/app.component.ts
@@ -1,38 +1,19 @@
import { Component } from '@angular/core';
+import { RouterModule } from '@angular/router';
import { GridJsAngularComponent } from 'gridjs-angular';
-import { faker } from '@faker-js/faker';
-import { TData } from 'gridjs/dist/src/types';
+import 'gridjs/dist/theme/mermaid.css';
@Component({
- selector: 'gridjs-angular-root',
standalone: true,
- imports: [GridJsAngularComponent],
- template: ``,
+ imports: [GridJsAngularComponent, RouterModule],
+ selector: 'gridjs-angular-root',
+ templateUrl: './app.component.html',
+ styleUrl: './app.component.css',
})
export class AppComponent {
- onLoad = (event: any) => console.log('Grid loaded', event);
- onBeforeLoad = (event: any) => console.log('Before grid loaded', event);
- onReady = (event: any) => console.log('Grid ready', event);
- onCellClick = (event: any) => console.log('Grid cell clicked', event);
- onRowClick = (event: any) => console.log('Grid row clicked', event);
-
columns = ['Name', 'Email', 'Phone Number'];
- data: TData = new Array(20)
- .fill(undefined)
- .map(() => [
- faker.person.fullName(),
- faker.internet.email(),
- faker.phone.number(),
- ]);
+ data = [
+ ['John', 'john@example.com', '(353) 01 222 3333'],
+ ['Mark', 'mark@gmail.com', '(01) 22 888 4444'],
+ ];
}
diff --git a/apps/demo/src/app/app.config.ts b/apps/demo/src/app/app.config.ts
new file mode 100644
index 0000000..ed40494
--- /dev/null
+++ b/apps/demo/src/app/app.config.ts
@@ -0,0 +1,7 @@
+import { ApplicationConfig } from '@angular/core';
+import { provideRouter } from '@angular/router';
+import { appRoutes } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+ providers: [provideRouter(appRoutes)],
+};
diff --git a/apps/demo/src/app/app.routes.ts b/apps/demo/src/app/app.routes.ts
new file mode 100644
index 0000000..8762dfe
--- /dev/null
+++ b/apps/demo/src/app/app.routes.ts
@@ -0,0 +1,3 @@
+import { Route } from '@angular/router';
+
+export const appRoutes: Route[] = [];
diff --git a/apps/demo/src/main.ts b/apps/demo/src/main.ts
index 57c05db..514c89a 100644
--- a/apps/demo/src/main.ts
+++ b/apps/demo/src/main.ts
@@ -1,6 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
+import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
-bootstrapApplication(AppComponent).catch((err) =>
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
console.error(err)
);
diff --git a/apps/demo/src/styles.css b/apps/demo/src/styles.css
new file mode 100644
index 0000000..90d4ee0
--- /dev/null
+++ b/apps/demo/src/styles.css
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/package.json b/package.json
index b9244c0..5e1a79b 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,6 @@
"@angular/cli": "~17.1.2",
"@angular/compiler-cli": "~17.1.2",
"@angular/language-service": "~17.1.2",
- "@faker-js/faker": "^8.4.0",
"@nx/devkit": "17.3.1",
"@nx/eslint": "17.3.1",
"@nx/eslint-plugin": "17.3.1",
@@ -50,7 +49,6 @@
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"autoprefixer": "^10.4.17",
- "change-case": "^5.4.2",
"eslint": "~8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-playwright": "^0.22.1",
@@ -58,7 +56,6 @@
"jest-environment-jsdom": "^29.7.0",
"jest-preset-angular": "~14.0.0",
"jsonc-eslint-parser": "^2.4.0",
- "mustache": "^4.2.0",
"ng-packagr": "~17.1.2",
"nx": "17.3.1",
"postcss": "^8.4.33",
diff --git a/packages/gridjs-angular/README.md b/packages/gridjs-angular/README.md
index e642626..e0fcd27 100644
--- a/packages/gridjs-angular/README.md
+++ b/packages/gridjs-angular/README.md
@@ -2,9 +2,6 @@
Angular wrapper for [Grid.js](https://github.com/grid-js/gridjs)
-[![gridjs-angular repository on GitHub](https://img.shields.io/badge/github-gridjs--angular-green?logo=github&link=https%3A%2F%2Fgithub.com%2Fgrid-js%2Fgridjs-angular)](https://github.com/grid-js/gridjs-angular)
-![GridJS peer Dependency Version](https://img.shields.io/npm/dependency-version/gridjs-angular/peer/gridjs)
-
## Install
```bash
@@ -30,7 +27,7 @@ In your component template
```ts
import { Component } from '@angular/core';
-import { Config } from 'gridjs';
+import { UserConfig } from 'gridjs';
@Component({
template: `
@@ -44,7 +41,7 @@ import { Config } from 'gridjs';
`
})
class ExampleComponent {
- public gridConfig: Config = {
+ public gridConfig: UserConfig = {
columns: ['Name', 'Email', 'Phone Number'],
data: [
['John', 'john@example.com', '(353) 01 222 3333'],
@@ -73,10 +70,13 @@ class ExampleComponent {
}
```
-Finally don't forget to add gridjs theme to your `angular.json` file, or import it some other way.
+Finally don't forget to add gridjs theme in your index.html
-```json
-styles: ["node_modules/gridjs/dist/theme/mermaid.min.css"]
+```html
+
```
## Inputs
@@ -89,7 +89,7 @@ styles: ["node_modules/gridjs/dist/theme/mermaid.min.css"]
## Outputs
-- You can bind to all Grid.js events as outputs. Additionally, the `load` event can also be accessed via `gridLoad` (to avoid conflict with the native DOM `load` event). See [Grid.js Events](https://gridjs.io/docs/examples/event-handler)
+- You can pass all Grid.js events as outputs with a little difference `load` event renamed to `beforeLoad`. See [Grid.js Events](https://gridjs.io/docs/examples/event-handler)
### Can I Grid.js rendering helpers? Yes
@@ -114,19 +114,4 @@ styles: ["node_modules/gridjs/dist/theme/mermaid.min.css"]
}
```
-### Can I use Angular template syntax in plugins, formatters, etc?
-
-Not currently.
-
-You can't use Angular template syntax in Grid.js plugins, formatters, etc. because they cannot be connected to Angular's change detection system. You can use `h` function or `html` function to create custom HTML for your grid.
-
-## Development
-
-The `gridjs-angular` repository is a monorepo that uses [Nx](https://nx.dev) and [pnpm](https://pnpm.io/).
-
-### Useful commands
-
-- `pnpm install` - Install all dependencies
-- `nx serve demo` - Run demo app
-- `nx migrate latest` - Update Nx to the latest version, and upgrade all packages from package.json to their latest version
-- `nx update-bindings gridjs-angular` - Update the input and output bindings from GridJS to the Angular component. This command should be run after updating the GridJS version.
+### Can I use Angular components in plugins, formatters, etc? Not yet
diff --git a/packages/gridjs-angular/package.json b/packages/gridjs-angular/package.json
index ee495b9..add10c2 100644
--- a/packages/gridjs-angular/package.json
+++ b/packages/gridjs-angular/package.json
@@ -14,8 +14,8 @@
"repository": "https://github.com/grid-js/gridjs-angular",
"license": "MIT",
"peerDependencies": {
- "@angular/common": ">=17",
- "@angular/core": ">=17",
+ "@angular/common": "^17.1.2",
+ "@angular/core": "^17.1.2",
"gridjs": "^6.1.1"
},
"dependencies": {
diff --git a/packages/gridjs-angular/project.json b/packages/gridjs-angular/project.json
index f791540..cb65ece 100644
--- a/packages/gridjs-angular/project.json
+++ b/packages/gridjs-angular/project.json
@@ -31,13 +31,6 @@
},
"lint": {
"executor": "@nx/eslint:lint"
- },
- "update-bindings": {
- "executor": "nx:run-commands",
- "outputs": ["{workspaceRoot}/packages/gridjs-angular/src/lib/gridjs-binding-base.ts"],
- "options": {
- "command": "node scripts/update-bindings.mjs"
- }
}
}
}
diff --git a/packages/gridjs-angular/src/index.ts b/packages/gridjs-angular/src/index.ts
index 96e1656..2a1c485 100644
--- a/packages/gridjs-angular/src/index.ts
+++ b/packages/gridjs-angular/src/index.ts
@@ -1,2 +1,2 @@
+export * from './lib/constants';
export * from './lib/gridjs-angular.component';
-export { GRID_EVENTS as GRID_JS_EVENTS } from './lib/gridjs-binding-base';
diff --git a/packages/gridjs-angular/src/lib/constants.ts b/packages/gridjs-angular/src/lib/constants.ts
new file mode 100644
index 0000000..7402548
--- /dev/null
+++ b/packages/gridjs-angular/src/lib/constants.ts
@@ -0,0 +1,35 @@
+import type { Config } from 'gridjs';
+import { GridEvents } from 'gridjs/dist/src/events';
+
+export const GRID_JS_EVENTS: (keyof GridEvents)[] = [
+ 'beforeLoad',
+ 'cellClick',
+ 'load',
+ 'rowClick',
+ 'ready',
+];
+
+export const GRID_JS_PROPS: (keyof Config)[] = [
+ 'eventEmitter',
+ 'plugin',
+ 'data',
+ 'server',
+ 'header',
+ 'from',
+ 'storage',
+ 'pipeline',
+ 'autoWidth',
+ 'width',
+ 'height',
+ 'translator',
+ 'style',
+ 'className',
+ 'fixedHeader',
+ 'columns',
+ 'search',
+ 'pagination',
+ 'sort',
+ 'language',
+ 'plugins',
+ 'processingThrottleMs',
+];
diff --git a/packages/gridjs-angular/src/lib/gridjs-angular.component.ts b/packages/gridjs-angular/src/lib/gridjs-angular.component.ts
index 357e5c2..4cce13c 100644
--- a/packages/gridjs-angular/src/lib/gridjs-angular.component.ts
+++ b/packages/gridjs-angular/src/lib/gridjs-angular.component.ts
@@ -3,73 +3,131 @@ import {
Component,
ElementRef,
EventEmitter,
+ Input,
+ OnChanges,
OnDestroy,
Output,
+ ViewEncapsulation,
} from '@angular/core';
+import { CommonModule } from '@angular/common';
import { Config, Grid } from 'gridjs';
-import { GRID_EVENTS, GridJsAngularBindingBase } from './gridjs-binding-base';
-import { GridEvents } from 'gridjs/dist/src/events';
-
-/** only properties that exist on the Config interface (not the Config class) */
-type EventName = keyof GridEvents;
-type EventHandler = (...args: any[]) => void;
+import { GRID_JS_EVENTS, GRID_JS_PROPS } from './constants';
+type GridJsAngularComponentProps = Omit<
+ Partial,
+ 'instance' | 'store' | 'assign' | 'update'
+>;
@Component({
selector: 'gridjs-angular',
- standalone: true,
template: '',
+ standalone: true,
+ imports: [CommonModule],
+ encapsulation: ViewEncapsulation.None,
})
export class GridJsAngularComponent
- extends GridJsAngularBindingBase
- implements AfterViewInit, OnDestroy
+ implements AfterViewInit, OnChanges, OnDestroy, GridJsAngularComponentProps
{
- private readonly listeners = new Map();
+ private nativeElement: HTMLElement;
+ private instance?: Grid;
+ private initialized = false;
+ private listeners: Map void> = new Map();
+ @Input() config?: Partial;
+ // TODO: auto generate Inputs/Output to easily sync with grid-js main package
+ // props
+ @Input() plugins: Config['plugins'] = [];
+ @Input() eventEmitter?: Config['eventEmitter'];
+ @Input() plugin?: Config['plugin'];
+ @Input() data: Config['data'];
+ @Input() server: Config['server'];
+ @Input() header: Config['header'];
+ @Input() from?: Config['from'];
+ @Input() storage?: Config['storage'];
+ @Input() pipeline?: Config['pipeline'];
+ @Input() autoWidth?: Config['autoWidth'];
+ @Input() width?: Config['width'];
+ @Input() height?: Config['height'];
+ @Input() translator?: Config['translator'];
+ @Input() style: Config['style'];
+ @Input() className: Config['className'];
+ @Input() fixedHeader?: Config['fixedHeader'];
+ @Input() columns?: Config['columns'];
+ @Input() search?: Config['search'];
+ @Input() pagination?: Config['pagination'];
+ @Input() sort?: Config['sort'];
+ @Input() language?: Config['language'];
+ @Input() resizable?: Config['resizable'];
+ @Input() processingThrottleMs?: Config['processingThrottleMs'];
- /** alias of `load` event due to possible conflict with native load event */
- @Output() readonly gridLoad = this.load;
+ // events
+ @Output() beforeLoad: EventEmitter = new EventEmitter(true);
+ // renamed load event to avoid conflict with native load event
+ @Output() gridLoad: EventEmitter = new EventEmitter(true);
+ @Output() cellClick: EventEmitter = new EventEmitter(true);
+ @Output() rowClick: EventEmitter = new EventEmitter(true);
+ @Output() ready: EventEmitter = new EventEmitter(true);
- constructor(private readonly host: ElementRef) {
- super();
+ constructor(private elementDef: ElementRef) {
+ this.nativeElement = this.elementDef.nativeElement;
}
ngAfterViewInit(): void {
- const instance = new Grid(this.config());
- this.instance.set(instance);
+ this.instance = new Grid(this.getConfig(this.config ?? {}));
this.registerEvents();
- instance.render(this.host.nativeElement);
+ this.instance.render(this.nativeElement);
+ this.initialized = true;
}
- ngOnDestroy(): void {
- if (this.instance()) {
- this.unregisterEvents();
- this.instance.set(undefined);
+ ngOnChanges(): void {
+ if (this.initialized) {
+ this.updateConfig(this.config);
}
}
+ ngOnDestroy(): void {
+ if (this.initialized) {
+ if (this.instance) {
+ this.unregisterEvents();
+ this.instance = undefined;
+ }
+ }
+ }
// public api to interact with grid instance
getGridInstance() {
- return this.instance();
+ return this.instance;
}
updateConfig(config: Partial = {}) {
- this.gridConfig.set(config);
+ this.instance?.updateConfig(this.getConfig(config)).forceRender();
}
private registerEvents() {
- for (const event of GRID_EVENTS) {
- const emitter = (this)[event] as EventEmitter;
- if (!emitter) {
- continue;
- }
+ for (const event of GRID_JS_EVENTS) {
+ const emitter =
+ event === 'load'
+ ? this.gridLoad
+ : >(this)[event];
const listener = (...args: any[]) => emitter.emit(args);
this.listeners.set(event, listener);
- this.instance()?.on(event, listener);
+ if (emitter) {
+ this.instance?.on(event as any, listener);
+ }
}
}
private unregisterEvents() {
for (const [event, listener] of this.listeners.entries()) {
- this.instance()?.off(event, listener);
+ this.instance?.off(event as any, listener);
+ }
+ }
+
+ private getConfig(config: Partial = {}) {
+ const newConfig = structuredClone(config);
+ for (const [key, value] of Object.entries(this)) {
+ if (GRID_JS_PROPS.includes(key as any)) {
+ (newConfig as any)[key] = value;
+ }
}
+ this.config = newConfig;
+ return newConfig;
}
}
diff --git a/packages/gridjs-angular/src/lib/gridjs-binding-base.ts b/packages/gridjs-angular/src/lib/gridjs-binding-base.ts
deleted file mode 100644
index 307294d..0000000
--- a/packages/gridjs-angular/src/lib/gridjs-binding-base.ts
+++ /dev/null
@@ -1,486 +0,0 @@
-// This file is generated automatically using "nx update-bindings gridjs-angular"
-// Do not edit this file manually
-import { Config } from 'gridjs';
-import { GridEvents } from 'gridjs/dist/src/events';
-import { Component, Input, Output, EventEmitter, signal, computed, effect } from '@angular/core';
-import 'preact';
-
-type GridEventsEmitter = Record>;
-
-export const GRID_EVENTS: Array = [
- 'beforeLoad',
- 'load',
- 'ready',
- 'cellClick',
- 'rowClick',
-];
-
-@Component({ template: '' })
-export abstract class GridJsAngularBindingBase implements GridEventsEmitter {
- constructor() {
- effect(() => {
- const instanceVal = this.instance();
- const instance = this.instance();
- if (instanceVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ instance: instanceVal });
- instance.forceRender();
- });
- effect(() => {
- const storeVal = this.store();
- const instance = this.instance();
- if (storeVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ store: storeVal });
- instance.forceRender();
- });
- effect(() => {
- const eventEmitterVal = this.eventEmitter();
- const instance = this.instance();
- if (eventEmitterVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ eventEmitter: eventEmitterVal });
- instance.forceRender();
- });
- effect(() => {
- const pluginVal = this.plugin();
- const instance = this.instance();
- if (pluginVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ plugin: pluginVal });
- instance.forceRender();
- });
- effect(() => {
- const containerVal = this.container();
- const instance = this.instance();
- if (containerVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ container: containerVal });
- instance.forceRender();
- });
- effect(() => {
- const tableRefVal = this.tableRef();
- const instance = this.instance();
- if (tableRefVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ tableRef: tableRefVal });
- instance.forceRender();
- });
- effect(() => {
- const dataVal = this.data();
- const instance = this.instance();
- if (dataVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ data: dataVal });
- instance.forceRender();
- });
- effect(() => {
- const serverVal = this.server();
- const instance = this.instance();
- if (serverVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ server: serverVal });
- instance.forceRender();
- });
- effect(() => {
- const headerVal = this.header();
- const instance = this.instance();
- if (headerVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ header: headerVal });
- instance.forceRender();
- });
- effect(() => {
- const fromVal = this.from();
- const instance = this.instance();
- if (fromVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ from: fromVal });
- instance.forceRender();
- });
- effect(() => {
- const storageVal = this.storage();
- const instance = this.instance();
- if (storageVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ storage: storageVal });
- instance.forceRender();
- });
- effect(() => {
- const processingThrottleMsVal = this.processingThrottleMs();
- const instance = this.instance();
- if (processingThrottleMsVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ processingThrottleMs: processingThrottleMsVal });
- instance.forceRender();
- });
- effect(() => {
- const pipelineVal = this.pipeline();
- const instance = this.instance();
- if (pipelineVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ pipeline: pipelineVal });
- instance.forceRender();
- });
- effect(() => {
- const autoWidthVal = this.autoWidth();
- const instance = this.instance();
- if (autoWidthVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ autoWidth: autoWidthVal });
- instance.forceRender();
- });
- effect(() => {
- const widthVal = this.width();
- const instance = this.instance();
- if (widthVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ width: widthVal });
- instance.forceRender();
- });
- effect(() => {
- const heightVal = this.height();
- const instance = this.instance();
- if (heightVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ height: heightVal });
- instance.forceRender();
- });
- effect(() => {
- const paginationVal = this.pagination();
- const instance = this.instance();
- if (paginationVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ pagination: paginationVal });
- instance.forceRender();
- });
- effect(() => {
- const sortVal = this.sort();
- const instance = this.instance();
- if (sortVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ sort: sortVal });
- instance.forceRender();
- });
- effect(() => {
- const translatorVal = this.translator();
- const instance = this.instance();
- if (translatorVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ translator: translatorVal });
- instance.forceRender();
- });
- effect(() => {
- const fixedHeaderVal = this.fixedHeader();
- const instance = this.instance();
- if (fixedHeaderVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ fixedHeader: fixedHeaderVal });
- instance.forceRender();
- });
- effect(() => {
- const resizableVal = this.resizable();
- const instance = this.instance();
- if (resizableVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ resizable: resizableVal });
- instance.forceRender();
- });
- effect(() => {
- const columnsVal = this.columns();
- const instance = this.instance();
- if (columnsVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ columns: columnsVal });
- instance.forceRender();
- });
- effect(() => {
- const searchVal = this.search();
- const instance = this.instance();
- if (searchVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ search: searchVal });
- instance.forceRender();
- });
- effect(() => {
- const languageVal = this.language();
- const instance = this.instance();
- if (languageVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ language: languageVal });
- instance.forceRender();
- });
- effect(() => {
- const pluginsVal = this.plugins();
- const instance = this.instance();
- if (pluginsVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ plugins: pluginsVal });
- instance.forceRender();
- });
- effect(() => {
- const styleVal = this.style();
- const instance = this.instance();
- if (styleVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ style: styleVal });
- instance.forceRender();
- });
- effect(() => {
- const classNameVal = this.className();
- const instance = this.instance();
- if (classNameVal === undefined || !instance) {
- return;
- }
- instance.updateConfig({ className: classNameVal });
- instance.forceRender();
- });
- }
-
- readonly instance = signal(undefined);
- @Input({alias: 'instance'})
- set _instance(value: Config['instance'] | undefined) {
- this.instance.set(value);
- }
-
- readonly store = signal(undefined);
- @Input({alias: 'store'})
- set _store(value: Config['store'] | undefined) {
- this.store.set(value);
- }
-
- readonly eventEmitter = signal(undefined);
- @Input({alias: 'eventEmitter'})
- set _eventEmitter(value: Config['eventEmitter'] | undefined) {
- this.eventEmitter.set(value);
- }
-
- readonly plugin = signal(undefined);
- @Input({alias: 'plugin'})
- set _plugin(value: Config['plugin'] | undefined) {
- this.plugin.set(value);
- }
-
- readonly container = signal(undefined);
- @Input({alias: 'container'})
- set _container(value: Config['container'] | undefined) {
- this.container.set(value);
- }
-
- readonly tableRef = signal(undefined);
- @Input({alias: 'tableRef'})
- set _tableRef(value: Config['tableRef'] | undefined) {
- this.tableRef.set(value);
- }
-
- readonly data = signal(undefined);
- @Input({alias: 'data'})
- set _data(value: Config['data'] | undefined) {
- this.data.set(value);
- }
-
- readonly server = signal(undefined);
- @Input({alias: 'server'})
- set _server(value: Config['server'] | undefined) {
- this.server.set(value);
- }
-
- readonly header = signal(undefined);
- @Input({alias: 'header'})
- set _header(value: Config['header'] | undefined) {
- this.header.set(value);
- }
-
- readonly from = signal(undefined);
- @Input({alias: 'from'})
- set _from(value: Config['from'] | undefined) {
- this.from.set(value);
- }
-
- readonly storage = signal(undefined);
- @Input({alias: 'storage'})
- set _storage(value: Config['storage'] | undefined) {
- this.storage.set(value);
- }
-
- readonly processingThrottleMs = signal(undefined);
- @Input({alias: 'processingThrottleMs'})
- set _processingThrottleMs(value: Config['processingThrottleMs'] | undefined) {
- this.processingThrottleMs.set(value);
- }
-
- readonly pipeline = signal(undefined);
- @Input({alias: 'pipeline'})
- set _pipeline(value: Config['pipeline'] | undefined) {
- this.pipeline.set(value);
- }
-
- readonly autoWidth = signal(undefined);
- @Input({alias: 'autoWidth'})
- set _autoWidth(value: Config['autoWidth'] | undefined) {
- this.autoWidth.set(value);
- }
-
- readonly width = signal(undefined);
- @Input({alias: 'width'})
- set _width(value: Config['width'] | undefined) {
- this.width.set(value);
- }
-
- readonly height = signal(undefined);
- @Input({alias: 'height'})
- set _height(value: Config['height'] | undefined) {
- this.height.set(value);
- }
-
- readonly pagination = signal(undefined);
- @Input({alias: 'pagination'})
- set _pagination(value: Config['pagination'] | undefined) {
- this.pagination.set(value);
- }
-
- readonly sort = signal(undefined);
- @Input({alias: 'sort'})
- set _sort(value: Config['sort'] | undefined) {
- this.sort.set(value);
- }
-
- readonly translator = signal(undefined);
- @Input({alias: 'translator'})
- set _translator(value: Config['translator'] | undefined) {
- this.translator.set(value);
- }
-
- readonly fixedHeader = signal(undefined);
- @Input({alias: 'fixedHeader'})
- set _fixedHeader(value: Config['fixedHeader'] | undefined) {
- this.fixedHeader.set(value);
- }
-
- readonly resizable = signal(undefined);
- @Input({alias: 'resizable'})
- set _resizable(value: Config['resizable'] | undefined) {
- this.resizable.set(value);
- }
-
- readonly columns = signal(undefined);
- @Input({alias: 'columns'})
- set _columns(value: Config['columns'] | undefined) {
- this.columns.set(value);
- }
-
- readonly search = signal(undefined);
- @Input({alias: 'search'})
- set _search(value: Config['search'] | undefined) {
- this.search.set(value);
- }
-
- readonly language = signal(undefined);
- @Input({alias: 'language'})
- set _language(value: Config['language'] | undefined) {
- this.language.set(value);
- }
-
- readonly plugins = signal(undefined);
- @Input({alias: 'plugins'})
- set _plugins(value: Config['plugins'] | undefined) {
- this.plugins.set(value);
- }
-
- readonly style = signal(undefined);
- @Input({alias: 'style'})
- set _style(value: Config['style'] | undefined) {
- this.style.set(value);
- }
-
- readonly className = signal(undefined);
- @Input({alias: 'className'})
- set _className(value: Config['className'] | undefined) {
- this.className.set(value);
- }
-
- readonly gridConfig = signal | undefined>(undefined);
- @Input({alias: 'gridConfig'})
- set _gridConfig(value: Partial | undefined) {
- this.gridConfig.set(value);
- }
-
- readonly config = computed>(() => {
- const configValue: Partial = {
- instance: this.instance(),
- store: this.store(),
- eventEmitter: this.eventEmitter(),
- plugin: this.plugin(),
- container: this.container(),
- tableRef: this.tableRef(),
- data: this.data(),
- server: this.server(),
- header: this.header(),
- from: this.from(),
- storage: this.storage(),
- processingThrottleMs: this.processingThrottleMs(),
- pipeline: this.pipeline(),
- autoWidth: this.autoWidth(),
- width: this.width(),
- height: this.height(),
- pagination: this.pagination(),
- sort: this.sort(),
- translator: this.translator(),
- fixedHeader: this.fixedHeader(),
- resizable: this.resizable(),
- columns: this.columns(),
- search: this.search(),
- language: this.language(),
- plugins: this.plugins(),
- style: this.style(),
- className: this.className(),
- };
- for(let key in configValue) {
- const keyName = key as keyof Config;
- if (configValue[keyName] === undefined) {
- delete configValue[keyName];
- }
- }
- return {
- ...this.gridConfig(),
- ...configValue
- };
- });
-
- @Output()
- readonly beforeLoad = new EventEmitter();
- @Output()
- readonly load = new EventEmitter();
- @Output()
- readonly ready = new EventEmitter();
- @Output()
- readonly cellClick = new EventEmitter();
- @Output()
- readonly rowClick = new EventEmitter();
-}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cf618b4..90a8d7c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -73,9 +73,6 @@ devDependencies:
'@angular/language-service':
specifier: ~17.1.2
version: 17.1.2
- '@faker-js/faker':
- specifier: ^8.4.0
- version: 8.4.0
'@nx/devkit':
specifier: 17.3.1
version: 17.3.1(nx@17.3.1)
@@ -127,9 +124,6 @@ devDependencies:
autoprefixer:
specifier: ^10.4.17
version: 10.4.17(postcss@8.4.33)
- change-case:
- specifier: ^5.4.2
- version: 5.4.2
eslint:
specifier: ~8.56.0
version: 8.56.0
@@ -151,9 +145,6 @@ devDependencies:
jsonc-eslint-parser:
specifier: ^2.4.0
version: 2.4.0
- mustache:
- specifier: ^4.2.0
- version: 4.2.0
ng-packagr:
specifier: ~17.1.2
version: 17.1.2(@angular/compiler-cli@17.1.2)(tslib@2.6.2)(typescript@5.3.3)
@@ -3324,11 +3315,6 @@ packages:
resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- /@faker-js/faker@8.4.0:
- resolution: {integrity: sha512-htW87352wzUCdX1jyUQocUcmAaFqcR/w082EC8iP/gtkF0K+aKcBp0hR5Arb7dzR8tQ1TrhE9DNa5EbJELm84w==}
- engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'}
- dev: true
-
/@fastify/busboy@2.1.0:
resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==}
engines: {node: '>=14'}
@@ -6010,10 +5996,6 @@ packages:
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
- /change-case@5.4.2:
- resolution: {integrity: sha512-WB3UiTDpT+vrTilAWaJS4gaIH/jc1He4H9f6erQvraUYas90uWT0JOYFkG1imdNv710XJ6gJvqynrgOHc4ihDA==}
- dev: true
-
/char-regex@1.0.2:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
@@ -9109,11 +9091,6 @@ packages:
dns-packet: 5.6.1
thunky: 1.1.0
- /mustache@4.2.0:
- resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
- hasBin: true
- dev: true
-
/mute-stream@1.0.0:
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
diff --git a/scripts/gridjs-binding-base.mustache b/scripts/gridjs-binding-base.mustache
deleted file mode 100644
index fd3d7a4..0000000
--- a/scripts/gridjs-binding-base.mustache
+++ /dev/null
@@ -1,80 +0,0 @@
-// This file is generated automatically using "nx update-bindings gridjs-angular"
-// Do not edit this file manually
-{{#inputTypes}}
-import { {{typeName}} } from '{{&importPath}}';
-{{/inputTypes}}
-{{#outputTypes}}
-import { {{typeName}} } from '{{&importPath}}';
-{{/outputTypes}}
-import { Component, Input, Output, EventEmitter, signal, computed, effect } from '@angular/core';
-import 'preact';
-
-{{#outputTypes}}
-type {{typeName}}Emitter = Record>;
-{{/outputTypes}}
-
-{{#outputTypes}}
-export const {{#constantCase}}{{typeName}}{{/constantCase}}: Array = [
- {{#members}}
- '{{.}}',
- {{/members}}
-];
-{{/outputTypes}}
-
-@Component({ template: '' })
-export abstract class GridJsAngularBindingBase implements GridEventsEmitter {
- constructor() {
- {{#inputTypes}}{{#members}}
- effect(() => {
- const {{.}}Val = this.{{.}}();
- const instance = this.instance();
- if ({{.}}Val === undefined || !instance) {
- return;
- }
- instance.updateConfig({ {{.}}: {{.}}Val });
- instance.forceRender();
- });
- {{/members}}{{/inputTypes}}
- }
-
-{{#inputTypes}}
- {{#members}}
- readonly {{.}} = signal<{{typeName}}['{{.}}'] | undefined>(undefined);
- @Input({alias: '{{.}}'})
- set _{{.}}(value: {{typeName}}['{{.}}'] | undefined) {
- this.{{.}}.set(value);
- }
-
- {{/members}}
- readonly gridConfig = signal | undefined>(undefined);
- @Input({alias: 'gridConfig'})
- set _gridConfig(value: Partial<{{typeName}}> | undefined) {
- this.gridConfig.set(value);
- }
-
- readonly {{#camelCase}}{{typeName}}{{/camelCase}} = computed>(() => {
- const {{#camelCase}}{{typeName}}Value{{/camelCase}}: Partial<{{typeName}}> = {
- {{#members}}
- {{.}}: this.{{.}}(),
- {{/members}}
- };
- for(let key in {{#camelCase}}{{typeName}}Value{{/camelCase}}) {
- const keyName = key as keyof {{typeName}};
- if ({{#camelCase}}{{typeName}}Value{{/camelCase}}[keyName] === undefined) {
- delete {{#camelCase}}{{typeName}}Value{{/camelCase}}[keyName];
- }
- }
- return {
- ...this.gridConfig(),
- ...{{#camelCase}}{{typeName}}Value{{/camelCase}}
- };
- });
-{{/inputTypes}}
-
-{{#outputTypes}}
- {{#members}}
- @Output()
- readonly {{.}} = new EventEmitter();
- {{/members}}
-{{/outputTypes}}
-}
diff --git a/scripts/update-bindings.mjs b/scripts/update-bindings.mjs
deleted file mode 100644
index d97f330..0000000
--- a/scripts/update-bindings.mjs
+++ /dev/null
@@ -1,103 +0,0 @@
-import ts from 'typescript';
-import { readFileSync, writeFileSync } from 'fs';
-import Mustache from 'mustache';
-import { camelCase, constantCase } from 'change-case';
-
-const config = {
- sourceTypings: [
- {
- path: 'node_modules/gridjs/dist/src/config.d.ts',
- importPath: 'gridjs',
- bindingTypes: 'input',
- },
- {
- path: 'node_modules/gridjs/dist/src/events.d.ts',
- importPath: 'gridjs/dist/src/events',
- bindingTypes: 'output',
- },
- ],
- bindingClassTemplate: 'scripts/gridjs-binding-base.mustache',
- outputPath: 'packages/gridjs-angular/src/lib/gridjs-binding-base.ts',
-};
-
-const mustacheHelpers = {
- camelCase: () => (text, render) => camelCase(render(text)),
- constantCase: () => (text, render) => constantCase(render(text)),
- noTrailingComma: () => (text, render) => {
- const result = render(text);
- return result.endsWith(',') ? result.slice(0, -1) : result;
- },
-};
-const template = readFileSync(config.bindingClassTemplate, 'utf-8');
-
-const types = extractTypeInformation(config.sourceTypings);
-
-const contents = Mustache.render(template, {
- inputTypes: types.filter((t) => t.bindingTypes === 'input'),
- outputTypes: types.filter((t) => t.bindingTypes === 'output'),
- ...mustacheHelpers,
-});
-writeFileSync(config.outputPath, contents);
-
-function extractTypeInformation(sourceTypings) {
- return sourceTypings.map(({ path, bindingTypes, importPath }) => {
- const program = ts.createProgram({
- rootNames: [path],
- options: {},
- });
- const checker = program.getTypeChecker();
- const sourceFile = program.getSourceFile(path);
- if (!sourceFile) {
- return;
- }
-
- return ts.forEachChild(sourceFile, (node) => {
- if (ts.isInterfaceDeclaration(node)) {
- const symbol = checker.getSymbolAtLocation(node.name);
- if (!symbol) {
- return;
- }
-
- const name = symbol.getName();
- const members = [...symbol.members.entries()]
- .map((m) => ({
- name: m[0],
- valueDeclaration: m[1].valueDeclaration,
- }))
- .filter(
- (m) => m.valueDeclaration?.kind === ts.SyntaxKind.PropertySignature,
- )
- .map((m) => m.name);
- return {
- typeName: name,
- bindingTypes,
- importPath,
- members,
- };
- } else if (ts.isTypeAliasDeclaration(node)) { // export type GridEvents = ContainerEvents & TableEvents;
- const srcType = checker.getTypeAtLocation(node);
- if (srcType.isIntersection()) {
- const members = [];
- srcType.types.forEach((t) => {
- const symbol = t.getSymbol();
- if (!symbol) {
- console.warn('No symbol found for type', t);
- return;
- }
- const declaration = symbol.getDeclarations()?.[0];
- if (ts.isInterfaceDeclaration(declaration)) { // ContainerEvents & TableEvents are both interfaces
- declaration.members.forEach(m => members.push(m.name?.getText()));
- }
- });
-
- return {
- typeName: node.name.getText(),
- bindingTypes,
- importPath,
- members,
- };
- }
- }
- });
- });
-}