Using agSelectCellEditor to populate Angular Grid dropdowns with values from a database

Utilizing refData and agSelectCellEditor in Angular 8 to display dropdown values during editing. I found a solution at the following link:

https://www.ag-grid.com/javascript-grid-reference-data/

However, the dropdown list data is fetched from the Database through an HTTP GET query. I am using "cellEditorParams" in agGrid, which includes the "extractValues()" method as shown below. The issue arises when the method runs before the data is retrieved from the Database, resulting in blank data. How can this problem be resolved?

Ideally, the dropdown should display values like "Yes/No". When I manually declare "objCategoryMappings" at the beginning with a static list, it works fine. Is there a limitation when it comes to using "refData" with dynamic lists from the database? If so, what is the alternative solution?

https://i.sstatic.net/LaO7D.png

Please refer to the code below. For simplicity, I have set "Yes/No" statically inside the subscribe method. In a real scenario, I would use "objCategoryMappings" to store values from the database.

HTML

<ag-grid-angular class="ag-theme-balham" [gridOptions]="categoryGridOptions"
            [rowData]="categoryRowData" [columnDefs]="categoryColDef"  
            (gridReady)="onGridReady($event)">
        </ag-grid-angular>

TS File

export class CategoryComponent{
  categoryRowData: any[]; 
  objCategoryMappings = {};

  constructor() {
        this.getAllCategories();                  
  } 

  getAllCategories()
    {            
        this.categoryCommonService.getEntityData('getallcatgories')
            .subscribe((rowData) => {                 
                this.categoryRowData = rowData;               
                this.objCategoryMappings["f"] = "No";
                this.objCategoryMappings["t"] = "Yes";                
            },
                (error) => { alert(error) });       
    }          

  categoryColDef = [
       {
            headerName: 'Category Name', field: 'CategoryName',                        
            cellEditor: 'agLargeTextCellEditor',
            cellEditorParams: {
                maxLength: '50',
                cols: '20',
                rows: '1'
            }
        },
        {
            headerName: 'Is Subcategory', field: 'IsSubcategory', //Values coming from db as "f" and "t"             
            cellEditor: 'agSelectCellEditor',
            cellEditorParams: {
                values: this.extractValues(this.objCategoryMappings),                                
            },                                                      
            refData: this.objCategoryMappings,            
        }];

    extractValues(mappings) {
        return Object.keys(mappings);
    }

}

Answer №1

Do you really need to build the objCategoryMappings object after retrieving the grid row data? It seems static and not dependent on the API response.

If you insist on keeping this approach, then consider defining the columns after receiving the API response since it relies on the objCategoryMappings data, which is currently undefined during definition:

export class CategoryComponent{
  categoryRowData: any[]; 
  objCategoryMappings = {};
  categoryColDef ;

  constructor() {
        this.getAllCategories();                  
  } 

 getAllCategories()
    {            
        this.categoryCommonService.getEntityData('getallcatgories')
            .subscribe((rowData) => {                 
                this.categoryRowData = rowData;               
                this.objCategoryMappings["f"] = "No";
                this.objCategoryMappings["t"] = "Yes";    
                this.createColumnsDefinition() ;            
            },
                (error) => { alert(error) });       
    }          

createColumnsDefinition(){
     this.categoryColDef = [
       {
            headerName: 'Category Name', field: 'CategoryName',                        
            cellEditor: 'agLargeTextCellEditor',
            cellEditorParams: {
                maxLength: '50',
                cols: '20',
                rows: '1'
            }
        },
        {
            headerName: 'Is Subcategory', field: 'IsSubcategory', //Values coming from db as "f" and "t"             
            cellEditor: 'agSelectCellEditor',
            cellEditorParams: {
                values: this.extractValues(this.objCategoryMappings),                                
            },                                                      
            refData: this.objCategoryMappings,            
        }];

...
}

Also, ensure that your HTML waits for the data to be received before rendering the grid, as mentioned by c_ogoo:

<ag-grid-angular
  *ngIf="categoryColDef" 
  class="ag-theme-balham" 
  [gridOptions]="categoryGridOptions"
  [rowData]="categoryRowData" 
  [columnDefs]="categoryColDef"  
  (gridReady)="onGridReady($event)"
>
</ag-grid-angular>

Answer №2

To determine when data should be displayed in the ag-grid component, you can make use of the ngIf directive.

<ag-grid-angular
  *ngIf="categoryRowData" 
  class="ag-theme-balham" 
  [gridOptions]="categoryGridOptions"
  [rowData]="categoryRowData" 
  [columnDefs]="categoryColDef"  
  (gridReady)="onGridReady($event)"
>
</ag-grid-angular>

By implementing this, the ag-grid component rendering will be postponed until the data is ready.

Answer №3

A different approach is available here. Instead of creating categoryColDef when data is received by the application, you can pre-create it and only update the objCategoryMappings. This method removes existing elements from objCategoryMappings whenever new data is received, preventing old data from persisting in the array. While you can also just add new data using the push() method, this solution ensures that only the latest data is present. I encountered this issue with Firebase, and I believe this method simplifies code management.

objCategoryMappings = [];

this.categoryCommonService.getEntityData('getallcatgories')
.subscribe((rowData) => {
    this.objCategoryMappings.length = 0;
    this.objCategoryMappings.push(...rowData);
});

cellEditor: 'agSelectCellEditor', cellEditorParams: { values: objCategoryMappings}

Here is an alternative solution where the data in rowData and objCategoryMappings is assumed to be in the same location. By comparing elements at corresponding locations, you can identify and update any changes in objCategoryMappings without replacing all values. This method can be highly efficient. (Note: This solution has not been tested like the previous one)

objCategoryMappings = [];

this.categoryCommonService.getEntityData('getallcatgories')
.subscribe((rowData) => {
    this.assign(rowData);
});

function assign(rowData){
    for(var i=0; i<rowData.length; i++) {
        if (rowData[i] != objCategoryMappings[i]) {
            objCategoryMappings[i] = rowData[i];
        }
    }
}

cellEditor: 'agSelectCellEditor', cellEditorParams: { values: objCategoryMappings}

You can set the length property to truncate an array at any time.

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

create the text with double bold - adjusted pages

Is there a method to enhance the boldness of the text without adjusting the font size? Currently, the following styling is applied: numbers: { fontSize: 30, color: '#31C283', fontWeight: 'bold', }, Is there a way to m ...

Can you explain how to incorporate a node module script into a React.js project?

I have encountered an issue where the element works perfectly fine when using an external node module, but fails to function properly when using a locally downloaded node module. Unfortunately, I am unable to identify the root cause of this problem. You c ...

Merging Type-GraphQL and Typegoose through a Variety of Decorators

Using a combination of Type-GraphQl and Typegoose, I aim to streamline my data definitions by consolidating them into one source for both GraphQL schemas and Mongoose queries. Is it feasible to merge the two libraries in a way that allows me to describe bo ...

What is causing the "excessive stack depth" error in this JSX code?

Exploring Next.js' TypeScript (4.2.3) functionality, I am utilizing it to compile the React component provided below. const Component = (): JSX.Element => { const categories = ['Fruit', 'Vegetables']; return ( <ul> ...

Unable to extract numerical value from object using Dropdown (Angular 4)

When I retrieve data from an API, everything works smoothly except when I try to bind my JSON option number value into the [value] tag. Here's an example: SUCCESSFUL (data retrieved from API is selected in the option) <select [(ngModel)]="data.fr ...

Tips for showcasing images stored in Azure Blob storage

Currently, I am developing an application that requires loading images from a web novel stored in Azure Storage Accounts as blobs. While I have enabled anonymous reads to show the image upon request successfully via a web browser or Postman, I am facing an ...

The lack of change detection triggering in Angular 8's UI observables could be due to the default setting of ChangeDetection

I am facing a situation where I have a container component with a service injected into it. The service holds an observable, and I am binding this observable to a child component's input property in the container component's template using an asy ...

What is the best way to organize the data retrieved from the api into a map?

In my search page component, I display the search results based on the user's query input. Here is the code snippet: "use client"; import { useSearchParams } from "next/navigation"; import useFetch from "../hooks/useFetch&qu ...

Potentially undefined object that may be nested and destructured

Here is a snippet of my auto-generated query types: export type MatchLivePlayerType = { __typename?: 'MatchLivePlayerType'; playbackData?: Maybe<MatchPlayerLivePlaybackDataType>; }; export type MatchPlayerLivePlaybackDataType = { __t ...

How can I import a node-js dependency into my webpack project when the package already comes with type definitions included?

Don't bother using the deprecated @types/chalk package because the chalk library already has type definitions included. But I keep encountering the error message TS2307: Cannot find module 'chalk'. https://i.sstatic.net/uDIJi.png The proje ...

JS selection-dropbox

As someone who is relatively new to JS, I am struggling a bit. The goal of the code is to display items with specific content (ALL, A, B, C). While the code works fine with buttons, I can't seem to get it to work with a 'Dropdown-select', ...

Pass an array of objects to an Angular 8 component for rendering

Recently, I started working with Angular 8 and faced an issue while trying to pass an array of objects to my component for displaying it in the UI. parent-component.ts import { Component, OnInit } from '@angular/core'; @Component({ selector: ...

Combine objects by selecting attributes from multiple objects

declare type A = {type: 'TypeA', attr1: string} declare type B = {type: 'TypeB', attr2: string} declare type U = A | B When I use type X = Pick<U, 'type'>, I get: { type: 'TypeA' | 'TypeB' } But I a ...

The Express server automatically shuts down following the completion of 5 GET requests

The functionality of this code is as expected, however, after the fifth GET request, it successfully executes the backend operation (storing data in the database) but does not log anything on the server and there are no frontend changes (ReactJS). const ex ...

Error: The function setIsEnabled does not exist

Currently, I am in the process of merging two separate next.js projects to create a website that can utilize the Cardano wallet 'Nami'. The code for accessing the wallet functions correctly in its original project, but when transferred over, it p ...

Creating an empty TypeScript variable with type FileList can be achieved by declaring the variable and initializing it with

After completing a coding test that required building a react app for uploading files using Typescript, I encountered a dilemma. Specifically, I needed to use the useState hook to store the uploaded file and set its default value. Typically, setting the de ...

How can I ensure that a particular component type passes the typescript check in a react-typescript project?

I'm fairly new to using TypeScript, although I have a lot of experience with React (and prop-types). Recently, I've run into an issue when it comes to typing my components, specifically when another component is passed as a prop. I already have ...

I'm new to Angular, so could you please explain this to me? I'm trying to understand the concept of `private todoItems: TodoItem[] = []`. I know `TodoItem` is an array that

//This pertains to the todoList class// The property name is todoItems, which is an array of TodoItem objects fetched from the TodoItem file. I am unable to make it private using "private todoItems: TodoItem[] = []," is this because of Dependency Injectio ...

Utilizing the useRef hook in React to retrieve elements for seamless page transitions with react-scroll

I've been working on creating a single-page website with a customized navbar using React instead of native JavaScript, similar to the example I found in this reference. My current setup includes a NavBar.tsx and App.tsx. The NavBar.tsx file consists o ...

Having trouble setting up Typescript in VisualStudio 2015 due to the error message "exports is not defined"? Need guidance on the correct setup?

I am new to TypeScript and I am currently learning about exports and imports in TypeScript However, as I started working on it, I encountered an error with exports Object.defineProperty(exports, "__esModule", { value: true }); The error message I receiv ...