Develop a specialized data structure for rows in ag grid that can adapt to changes

I have been working on creating an independent component using ag-grid. The column definitions are passed to this component from my application as input properties, defined like this:

interface ColumnDef {
  field: string;
  headerName: string;
}

@Input() colDef: ColumnDef[];

Currently, I am able to pass different sets of columns from the host application to the common component with unique IDs.

However, now I have a new requirement where I need to dynamically define the row data type for ag-grid inside the common component as well.

For example, if I pass column definitions like:

[{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'}]

The component should generate a row data type dynamically as follows:

interface rowData {
 colA: string;
 colB: string;
}

Similarly, if I pass more columns like:

[{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'},
{field: 'colC', headerName: 'Col C'}]

The row data type should be created accordingly:

interface rowData {
 colA: string;
 colB: string;
 colC: string;
}

This dynamic definition would allow me to use the interface for typing the row data effectively. Is there a way to achieve this functionality?

Thank you for your assistance.

Answer №1

If we consider an array structured like this:

const columnDefinitions = [
{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'},
{field: 'colC', headerName: 'Col C'}
] as const;

We can define the following types:

type FieldNames<T> = T extends ReadonlyArray<{ field: infer U }> ? U : never;

type Rows<T> = FieldNames<T> extends string ? Record<FieldNames<T>, string> : never;

Resulting in the outputs:

  • FieldNames<typeof columnDefinitions>
    is 'colA' | 'colB' | 'colC'
  • Rows<typeof columnDefinitions>
    is
    { colA: string; colB: string; colC: string }
    .

However, if your current ColumnDef type is used, typeof columnDefinitions will be ColumnDef, making

FieldNames<typeof columnDefinitions>
result in Record<string, string>, which is not very useful. To resolve this issue, introducing a type parameter to the component class is necessary:

class CustomGridComponent<T extends ColumnDef> implements OnInit /* or what have you */ { 
    @Input() columnDefinitions: ReadonlyArray<T> = [] as const;
    ... 
}

(It is worth noting that using ReadonlyArray allows for automatic generation of types for column definitions by appending as const at the end of the array. If manually defining an interface like

ABCColDef { field: 'colA' | 'colB' | 'colC'; ... }
is preferred, then omitting ReadonlyArray is acceptable.)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ag-Grid: A Guide to Storing and Restoring Columns with Filter Settings

Ag-Grid allows us to easily filter columns. One requirement I have is to save the column filter order in a SQL database backend. I have implemented a method for saving the column order, but it doesn't seem to work properly. onGridReady: function(par ...

How can I restart an asynchronous observable when the parameter changes?

My async observable is designed to take 2 parameters for calculation purposes: public preferredCurrency: string = ''; wmData$ = this.http.get<any>("./api/wealthModeling/GetWMData"); portfolioCalculation$ = this.wmData$.pipe ...

Angular: The type AbstractControl<any> cannot be assigned to type FormControl

I am working with a child component that includes an input tag <input [formControl]="control"> component.ts file @Input() control: FormControl; In the parent component, I am using it as follows: <app-input [control]="f['email ...

No data found in the subrow of the datasource after the filter has been

I am working with a material table that has expandable rows. Inside these expanded rows, there is another table with the same columns as the main table. Additionally, I have implemented filters in a form so that when the filter values change, I can update ...

The tab title will be invisible if it is located within the second Angular component

Currently, I am utilizing the material css framework in combination with Angular (both latest versions). Everything works perfectly fine when I create tabs within one component. However, when I decide to make each tab a separate component, an issue arises ...

Guide on setting up p-menubar in PrimeNG to expand in the opposite direction, from left to right, for the responsive

How can I modify the CSS styles or configure the p-menubar from PrimeNg to have it expand from right to left in the responsive version? Currently, when using the classes align-items-center flex justify-content-between, the menu remains stuck to the right e ...

Encountering error "An import path cannot end with a '.ts' extension." when importing TypeScript file in Vue Single File Component (SFC) within VS Code

Currently, I am in the process of transitioning my .vue components from using JavaScript to TypeScript. As a result, my single file components are structured as follows: <template> ...something... </template> <script lang="ts"> import ...

Transforming Angular 4's folder structure for improved architecture simplicity

I am faced with the challenge of organizing files and folders within an Angular 4 project in a way that allows for easy reorganization. Currently, my approach looks like this: ├───core │ │ core.module.ts │ │ index.ts │ │ │ ...

Using Node-Forge for importing in an Angular 2 service

I've been attempting to incorporate Forge (https://github.com/digitalbazaar/forge) into my Angular 2 project. After executing the command :npm install node-forge, the node-forge directory was created within my application (in the node-modules directo ...

Unshifting values in a JavaScript array only if they exist in another array

I have two arrays of objects - one containing selected data and the other containing general data that needs to be displayed General data for display const arr = [ { id: "1", name: "Skoda - Auto" }, { id: "2" ...

Encountering an issue with Next.js, Typescript, and mongoose when attempting to use `let cached = global.mongoose

I attempted to create a cached mongoose connection for my Next.js + Typescript application, but the code I used was: let cached = global.mongoose; if (!cached) { cached = global.mongoose = { conn: null, promise: null }; } The use of global.mongoose res ...

What is the best way to create a mapping function in JavaScript/TypeScript that accepts multiple dynamic variables as parameters?

Explaining my current situation might be a bit challenging. Essentially, I'm utilizing AWS Dynamodb to execute queries and aiming to present them in a chart using NGX-Charts in Angular4. The data that needs to appear in the chart should follow this fo ...

Issue: Oops! The digital envelope routines are not supported in Angular while attempting to run the project

I encountered an error when running the command below: ng s The error message is as follows: Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:68:19)at Object.createHash (node:crypto:138:10)at BulkUpdateDe ...

Troubleshooting: The canvas texture in Phaser 3's Update() function is not functioning

I've been attempting to transform this tutorial into Phaser 3: but have encountered an issue with the update() function not working. I also tried using the refresh() function, but that didn't solve the problem either. In my file a.ts, I have cre ...

Choose does not showcase the updated value

My form contains a form control for currency selection Each currency object has the properties {id: string; symbol: string}; Upon initialization, the currency select component loops through an array of currencies; After meeting a specific condition, I need ...

What is the correct way to access and assign a value from a different getter or setter? I am facing an issue with the creation of my second array

Two http GET API calls are being made in the constructor. The first call is working fine and has a getter/setter to filter the main array (studentNameData) into a filtered array (filteredName). However, the second call is also trying to do the same thing b ...

Angular developers are struggling to find a suitable alternative for the deprecated "enter" function in the drag and drop CDK with versions 10 and above

By mistake, I was working on an older version of Angular in StackBlitz (a code-pane platform). I came across a function called enter on GitHub, but it didn't solve my issue. I was working on a grid-based drag and drop feature that allows dragging bet ...

Changing the ngModel value causes the maxlength to become ineffective

<input type="text" [(ngModel)]="name" maxlength="10"/> @Component({...}) export class MyComponent { name = "testtesttesttesttest"; // length = 20 } When the input field is displayed, it shows all 20 characters. What steps can be taken to prevent ...

implementing a function to execute after making a successful $http.get request

I have implemented ngrx-store and am attempting to activate a spinner before making an HTTP call, and disabling it once the call has been completed. getInspectionDetails(order) { this.store.dispatch({ type: SPINNER_VISIBLE, payload: true }) //<-- S ...

Tips for storing the returned value from an HTTP request in a variable in Angular 8

Recently, I encountered an issue while trying to make an HTTP call in Angular. Here is the code snippet: this.values = this.http.get("https://reqres.in/api/users/2").subscribe(data => console.log(data)) console.log(this.values) Surprisingly, the first ...