0
votes

I am implementing cell editing feature of ag-grid in my angular 7 application. I need to show dropdown value for one of the cells . I am setting the value for the dropdown in cellEditorParams. I can see the values are getting bound but not displaying the dropdown.Could somebody tell me what the problem here is

   cellEditorParams: {
      values: this.DocumentUploadDetails.DocumentTypes,
      cellRenderer: (params) => params.value.Name
    }

I suspect the issue is with this line cellRenderer: (params) => params.value.Name

I have implemented the following event for cellediting

     onCellClicked($event){
    // check whether the current row is already opened in edit or not
    if(this.editingRowIndex != $event.rowIndex) {
      console.log($event);
      $event.api.startEditingCell({
        rowIndex: $event.rowIndex,
        colKey: $event.column.colId
      });
      this.editingRowIndex = $event.rowIndex;
    }
  }

JSON

DocumentTypes is basically collection of Id and Name properties

[{"Id":4,"Name":"DD Questionnaires / Materials"},{"Id":6,"Name":"Constitutional Documents"},{"Id":7,"Name":"Regulation / References"},{"Id":8,"Name":"Email Correspondence"},{"Id":10,"Name":"Manager Letters"},{"Id":13,"Name":"Office Maps"},{"Id":14,"Name":"Quantitative"},{"Id":1,"Name":"Fund"},{"Id":20,"Name":"Other"},{"Id":21,"Name":"Fund DD Visit"},{"Id":23,"Name":"Investment Proposal"},{"Id":22,"Name":"Research Note"},{"Id":102,"Name":"Fund Organizational Document - Articles of Association"},{"Id":104,"Name":"Form ADV - Part 1"},{"Id":105,"Name":"Due Diligence Questionnaire"},{"Id":106,"Name":"Financial Statements"},{"Id":107,"Name":"Fund Organizational Document - Limited Partnership Agreement"},{"Id":108,"Name":"Investment Management Agreement"},{"Id":109,"Name":"Marketing Presentation"},{"Id":110,"Name":"Third Party Research - Morningstar Report"},{"Id":111,"Name":"Newsletter"},{"Id":112,"Name":"Offering Circular"},{"Id":113,"Name":"Side Letter"},{"Id":114,"Name":"Risk Exposure"},{"Id":115,"Name":"Redemption Form"},{"Id":116,"Name":"Offering Circular - Supplement"},{"Id":117,"Name":"Subscription Form - Additional Subscription"},{"Id":118,"Name":"Subscription Form - Non US Investor"},{"Id":119,"Name":"Subscription Form - US Tax Exempt"},{"Id":120,"Name":"Subscription Form - US Investor"},{"Id":123,"Name":"Termination Letter"},{"Id":125,"Name":"Corporate Communications"},{"Id":126,"Name":"Articles - News"},{"Id":127,"Name":"Detailed AUM"},{"Id":128,"Name":"Cube Risk Document"},{"Id":132,"Name":"Valuation Memo"},{"Id":133,"Name":"SEC 13F"},{"Id":134,"Name":"NAV Statements"},{"Id":135,"Name":"Corporate Action"},{"Id":137,"Name":"Form ADV - Part 2"},{"Id":138,"Name":"Third Party Research - Other"},{"Id":141,"Name":"Factor Analysis"},{"Id":142,"Name":"Peer Group"},{"Id":143,"Name":"Quant Report"},{"Id":144,"Name":"ODD Report"},{"Id":145,"Name":"Activity Note"},{"Id":146,"Name":"Certificates of Formation"},{"Id":147,"Name":"Financial Statements Audit"},{"Id":148,"Name":"Articles of Association"},{"Id":149,"Name":"Limited Partnership Agreement"},{"Id":150,"Name":"Subscription Documents"},{"Id":151,"Name":"Advisory Agreement"},{"Id":153,"Name":"1.1+Call%2fMeeting+Notes"},{"Id":100,"Name":"White Papers"},{"Id":101,"Name":"Summary of Terms"},{"Id":103,"Name":"Conference Presentation"},{"Id":154,"Name":"2.1+Monthly+Reports"},{"Id":155,"Name":"2.2%2bQtrly%252fSemi-Ann%252fAnnual%2bRpts"},{"Id":156,"Name":"2.3+Performance+%2f+Estimates"},{"Id":157,"Name":"3.1%2bPitchbook%252fPresentation%252fDDQ"},{"Id":158,"Name":"3rd Party Research - Mgr/Fund"},{"Id":159,"Name":"3rd Party Research - Position"},{"Id":160,"Name":"Account Statements"},{"Id":161,"Name":"Agreed-Upon Procedure (AUP) Reports"},{"Id":162,"Name":"Business Continuity Plans (BCP)"},{"Id":163,"Name":"Call/Meeting Notes"},{"Id":164,"Name":"Capital Call Letters"},{"Id":165,"Name":"Code of Ethics"},{"Id":166,"Name":"Compliance Manual"},{"Id":167,"Name":"Confidentiality Agreements"},{"Id":168,"Name":"Counterparty Exposure Report"},{"Id":169,"Name":"Distribution / Redemption Notices"},{"Id":170,"Name":"E-Mail Exchange (mgr items that don't belong to other sub-cats)"},{"Id":171,"Name":"EnTrust Allocation Memo"},{"Id":172,"Name":"EnTrust DDQ"},{"Id":173,"Name":"EnTrust Exposure Template"},{"Id":174,"Name":"EnTrust Exposure Templates"},{"Id":175,"Name":"EnTrust Expsoure Template"},{"Id":176,"Name":"EnTrust Investment Memos"},{"Id":177,"Name":"EnTrust ODD Checklist"},{"Id":178,"Name":"EnTrust ODD Meeting Notes"},{"Id":179,"Name":"EnTrust Operational Dashboard"},{"Id":180,"Name":"Exposure / Attribution"},{"Id":181,"Name":"FAS 157 Reporting"},{"Id":182,"Name":"Firm AUM History"},{"Id":183,"Name":"Firm SAS 70 (Type I or II) Reports"},{"Id":184,"Name":"Firm/Fund AUM History"},{"Id":185,"Name":"Flash Notes"},{"Id":186,"Name":"Form ADV Part I"},{"Id":187,"Name":"Form ADV Part II"},{"Id":188,"Name":"Fund DDQ"},{"Id":189,"Name":"Fund Personnel Biographies"},{"Id":190,"Name":"Fund Personnel Changes"},{"Id":191,"Name":"Fund Pitch Book / Marketing Deck"},{"Id":192,"Name":"Fund Pitch Book / Marketing Decks"},{"Id":193,"Name":"Fund Prospectus"},{"Id":194,"Name":"Fund Structure Chart"},{"Id":195,"Name":"Historical Exposure / Historical Attribution"},{"Id":196,"Name":"Investment Manager Agreement (IMA)"},{"Id":197,"Name":"Investor Type Breakout"},{"Id":198,"Name":"Key Personnel Background Checks"},{"Id":199,"Name":"LPA / LLC Agreement"},{"Id":200,"Name":"Limited Partnership Agreement (LPA)"},{"Id":201,"Name":"Liquidity Breakout"},{"Id":202,"Name":"Mail Correspondence"},{"Id":203,"Name":"Manager DDQ"},{"Id":204,"Name":"Manager Reporting"},{"Id":205,"Name":"Monthly Flash Call"},{"Id":206,"Name":"Monthly Reports"},{"Id":207,"Name":"Monthly Reports (Investor Letter, Exposure, Allocation)"},{"Id":208,"Name":"Most Favored Nations (MFN) / Side Letters"},{"Id":209,"Name":"OPERA"},{"Id":210,"Name":"Opportunistic Investments"},{"Id":211,"Name":"Organizational Chart"},{"Id":212,"Name":"Other Firm Policy"},{"Id":213,"Name":"Other Firm Reporting"},{"Id":214,"Name":"Other Operational Reporting"},{"Id":215,"Name":"Performance"},{"Id":216,"Name":"Performance / Estimates"},{"Id":217,"Name":"Personal Trading Policy"},{"Id":218,"Name":"Pitchbook, Presentation, Manager/Fund DDQ"},{"Id":219,"Name":"Private Placement Memorandum (PPM)"},{"Id":220,"Name":"Proxy Voting Policy"},{"Id":221,"Name":"Quarterly, Semi-Annual, Annual Reports"},{"Id":222,"Name":"Redemption Documents"},{"Id":223,"Name":"Research Clippings : Manager Level"},{"Id":224,"Name":"Research Clippings : Position Level"},{"Id":225,"Name":"Service Provider Agreements / Descriptions of Service"},{"Id":226,"Name":"Service Provider Confirmations / DDQs"},{"Id":227,"Name":"Service Provider SAS 70 (Type I or II) Reports"},{"Id":228,"Name":"Temp"},{"Id":229,"Name":"Trade Error Policy"},{"Id":230,"Name":"Trade Flow / Operational Processes"},{"Id":231,"Name":"Valuation / Pricing Review Support"},{"Id":232,"Name":"Valuation / Pricing Source Breakout"},{"Id":233,"Name":"Valuation Policy"},{"Id":234,"Name":"zz_(DD-ODD)"},{"Id":235,"Name":"zz_(Fund Info)"},{"Id":236,"Name":"zz_(Governing Docs)"},{"Id":237,"Name":"zz_(Other)"},{"Id":238,"Name":"Daily/Weekly/Monthly Letters/Reports"},{"Id":239,"Name":"Quarterly Letters/Reports"},{"Id":240,"Name":"Annual Letters/Reports"},{"Id":242,"Name":"Meeting Notes"},{"Id":243,"Name":"Weekly Performance"},{"Id":244,"Name":"Mid-Month Performance"},{"Id":245,"Name":"Monthly Performance"},{"Id":246,"Name":"Quarterly Flash Bullets"},{"Id":247,"Name":"Activity Attachment"},{"Id":249,"Name":"Trade Slide"}]

Html

<div class="card" *ngIf="DocumentUploadDetails && DocumentUploadDetails.DocumentEntities" style="margin-top: 10px" >
    <div class="card-body" style="width:100%; text-align: left;">
        <div style="overflow-x: hidden; overflow-y: hidden; ">
            <div class="form-group row">
                <div class="panel panel-default col-md-12  ">
                    <div class="panel-body">
                        <div id="grid-wrapper" [style.height.px]="GridHeight()" [style.width.%]="100"
                            style="float: left;">
                            <ag-grid-angular #agGrid class="ag-theme-balham" [gridOptions]="GridOptions"
                                style="width: 100%; height: 100%" [columnDefs]="ColumnDefs" rowHeight="30"
                                [rowData]="DocumentUploadDetails.DocumentEntities"
                                [editType]="editType"
                                (cellClicked)="onCellClicked($event)"
                                headerHeight="30" rowSelection="single">
                            </ag-grid-angular>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Component

import { Component, Injectable, NgZone, ViewEncapsulation, ViewChild, Input } from '@angular/core'
import { OnInit } from '@angular/core'
import { Comparator } from '../utilities/comparator';
import { GridOptions, GridApi } from 'ag-grid-community';
import { DocumentUploadService } from '../services/documentUpload.service';
import { NotifyService } from '../utilities/notify.service';
import { number } from '@amcharts/amcharts4/core';

@Component({
    selector: 'mgr-document-upload',
    templateUrl: './documentUpload.component.html'
})

export class DocumentUploadComponent implements OnInit {
    Files: Array<File>;
    ColumnDefs: Array<any> = new Array<any>();
    private Comparator: Comparator;
    private Error: string;
    private gridApi: GridApi;
    public GridOptions: GridOptions;
    private editClicked;
    private editingRowIndex;
    private editType;
    ngZone: any;
    windowHeight: any;
    offset: number;
    Loading: boolean;
    public DocumentUploadDetails: any;
    public params: any;
    @Input() ManagerStrategyId = 5508;
    MgrStrategyId = 5508;


    ngOnInit() {
        this.setGridOptions();
        this.getDocumentUploadDetails();
    }


    constructor(private comparator: Comparator, private documentUploadService : DocumentUploadService,  private notify: NotifyService,) {
        this.Comparator = comparator;
        this.editClicked = true;
        this.getDocumentUploadDetails();
        window.onresize = (e) => {
            this.ngZone.run(() => {
                this.windowHeight = window.innerHeight - this.offset;
                setTimeout(() => {
                    if (!this.GridOptions || !this.GridOptions.api) {
                        return;
                    }
                }, 500, true);
            });
        };

    }


    private getColumns(): Array<any> {
        const self = this;
        const columnDefs = new Array<any>();
        columnDefs.push({ headerName: 'ID', field: 'DocumentId', hide: true ,editable: false});
        columnDefs.push({ headerName: 'Document Type ID', field: 'DocumentTypeId', hide: true , editable: false});
        columnDefs.push({ headerName: 'Type', field: 'DocumentTypeName', hide: false , editable: true ,  cellEditor: 'agSelectCellEditor',
        cellEditorParams: {
          values: this.DocumentUploadDetails.DocumentTypes,
          cellRenderer: (params) => params.value.Name
        }
    });
        columnDefs.push({ headerName: 'Document', field: 'DocumentName', hide: false, editable: true });
        columnDefs.push({ headerName: 'Document Date', field: 'DocumentDate', hide: false , editable: true});

        columnDefs.push(
            {
                cellRenderer: function (p) {

                    if (p.node.data && p.node.data.DocumentId) {
                        var eSpan = self.getDeleteSpan();
                        eSpan.addEventListener('click', function () {
                            var self2 = self;
                            //self2.onEdit();
                        });
                        return eSpan;
                    }
                    else {
                        return '';
                    }
                }, comparator: this.comparator.StringComparator, width: 50, cellStyle: { textAlign: 'center' }, cellClass: 'align-center', headerName: "Edit", pinned: 'right'

            });


        columnDefs.push(
            {
                cellRenderer: function (p) {

                    if (p.node.data && p.node.data.DocumentId) {
                        var eSpan = self.getDeleteSpan();
                        eSpan.addEventListener('click', function () {
                            var self2 = self;
                            self2.Delete(p.node.data.DocumentId);
                        });
                        return eSpan;
                    }
                    else {
                        return '';
                    }
                }, comparator: this.comparator.StringComparator, width: 50, cellStyle: { textAlign: 'center' }, cellClass: 'align-center', headerName: "Delete", pinned: 'right'

            });


            this.editType = 'fullRow';

        return columnDefs;
    }

    onEdit() {
        // this.params =  this.GridOptions.api.getEditingCells;
        // this.editClicked = !this.editClicked;
        // this.params.api.setFocusedCell(this.params.node.rowIndex, 'action');
        // this.params.api.startEditingCell({
        //  rowIndex: this.params.node.rowIndex,
        //  colKey: 'action'
        // });
       }


    private getDeleteSpan() {
        var eSpan = document.createElement('a');
        eSpan.innerHTML = '<div style="cursor:pointer;max-width: 50px"><i class="far fa-trash-alt fontColor" aria-hidden="true"></i></div>';
        return eSpan;
    }

    GridHeight() {
        if (!this.windowHeight) {
            this.windowHeight = window.innerHeight - this.offset + 10;
        }
        return this.windowHeight;
    }

    private initGrid() {
        const self = this;
    }

    setGridOptions() {
        this.GridOptions = {
            columnDefs: this.getColumns(),
            enableFilter: true,
            enableColResize: true,
            animateRows: true,
            enableSorting: true,

            onGridReady: e => {
                if (!e || !e.api) {
                    return;
                }

                this.gridApi = e.api;

                this.setDefaultSortOrder();
            },
            onGridSizeChanged: () => this.GridOptions.api.sizeColumnsToFit(),



        };

    }

    onCellClicked($event){
        // check whether the current row is already opened in edit or not
        if(this.editingRowIndex != $event.rowIndex) {
          console.log($event);
          $event.api.startEditingCell({
            rowIndex: $event.rowIndex,
            colKey: $event.column.colId
          });
          this.editingRowIndex = $event.rowIndex;
        }
      }

    setDefaultSortOrder() {
        const defaultSortModel = [
            { colId: 'DocumentDate', sort: 'desc' }

        ];
        this.GridOptions.api.setSortModel(defaultSortModel);
    }


    onGridSizeChanged(params) {
        const gridWidth = document.getElementById('grid-wrapper').offsetWidth;
        const columnsToShow = [];
        const columnsToHide = [];
        let totalColsWidth = 0;
        const allColumns = params.columnApi.getAllColumns();
        for (let i = 0; i < allColumns.length; i++) {
            const column = allColumns[i];
            totalColsWidth += column.getMinWidth();
            if (totalColsWidth > gridWidth) {
                columnsToHide.push(column.colId);
            } else {
                columnsToShow.push(column.colId);
            }
        }
        params.columnApi.setColumnsVisible(columnsToShow, true);
        params.columnApi.setColumnsVisible(columnsToHide, false);
        params.api.sizeColumnsToFit();
    }

    private Delete(Id: number) {

            if (Id !== 0) {


                this.Error = '';
                this.documentUploadService
                    .deleteDocument(Id)
                    .then((result) => {
                        if (result) {
                            this.notify.success('Document Successfully Deleted');
                           // this.ClassficationOverrideDetailsEvent.next('init');
                        }
                    }).catch(err => {
                        this.notify.error('An Error Has Occured While Deleting Document');
                    });
            }

    }





    public getDocumentUploadDetails() {
        if (this.MgrStrategyId != null) {
            this.Loading = true;
            this.initGrid();

            //  this.spinner.show();
            this.documentUploadService.getDocumentUploadDetails(this.MgrStrategyId)
                .subscribe(data => {
                    this.DocumentUploadDetails = data;
                    this.ColumnDefs = this.getColumns();
                    this.Loading = false;

                    setTimeout(() => {
                        this.GridOptions.api.sizeColumnsToFit();
                        this.Loading = false;
                    }, 100, true);
                },
                    err => {
                        this.Error = 'An error has occurred. Please contact BSG';
                    },
                    () => {
                    });
        }
    }
}

Updated Code as per suggested solution

I have gone by the following option in order to use agSelectCellEditor

  this.DocumentTypesForDropDown = this.DocumentUploadDetails.DocumentTypes.map(x => x.Name);

I have also removed the calls to the this.getColumns() as suggested and moved it to the init method

My Init method now looks like this

   ngOnInit() {

        this.getDocumentUploadDetails();
        this.setGridOptions();
        this.setColumns();


    }

There is small change that I have made by setting the this.DocumentTypesForDropDown value in the getDocumentUploadDetails method as I am getting the DocumentTypes from the service.

public getDocumentUploadDetails() {
        if (this.MgrStrategyId != null) {
            this.Loading = true;
            this.initGrid();

            //  this.spinner.show();
            this.documentUploadService.getDocumentUploadDetails(this.MgrStrategyId)
                .subscribe(data => {
                    this.DocumentUploadDetails = data;
                    this.DocumentTypesForDropDown = this.DocumentUploadDetails.DocumentTypes.map(x => x.Name);

                   // this.ColumnDefs = this.getColumns();
                    this.Loading = false;

                    setTimeout(() => {
                        this.GridOptions.api.sizeColumnsToFit();
                        this.Loading = false;
                    }, 100, true);
                },
                    err => {
                        this.Error = 'An error has occurred. Please contact BSG';
                    },
                    () => {
                    });
        }
    }
}

After doing the above I am getting no errors and blank grid is getting displayed

Update 2

_documentTypes: any;
    get DocumentTypes(): any {
        return this._documentTypes;
    }
    @Input('DocumentTypes')
    set DocumentTypes(value: any) {
         this._documentTypes = value;
         if(this._documentTypes.length > 0) {
         this.DocumentTypesForDropDown = this._documentTypes.map(x => x.text);
         this.getDocumentUploadDetails();
        this.setGridOptions();
        this.setColumns();
         }
    }
1

1 Answers

0
votes

There are a number of problems with your code, and I'll try to address each of them.

Your main issue to do with the dropdown, you have the following code for your dropdown:

columnDefs.push({
  headerName: 'Type', field: 'DocumentTypeName', hide: false, editable: true, cellEditor: 'agSelectCellEditor',
  cellEditorParams: {
    values: this.DocumentUploadDetails.DocumentTypes,
    cellRenderer: (params) => params.value.Name
  }

When using the agSelectCellEditor, the only params you can pass to the cellEditorParams is values (see the documentation).

Therefore, if you'd like to use objects for your dropdown, you will need to use agRichSelectCellEditor which can handle objects. agrichselectcelleditor will have the cellRenderer paramater, although this is an enterprise feature of ag-grid.

Therefore, if you'd like to have your options by name within the dropdown, I suggest you create an array of your dropdown issues, and have just the document type name in there.

You can do something like this:

this.DocumentTypesForDropDown = this.DocumentUploadDetails.DocumentTypes.map(x => x.Name);

This will contain an array of all the document type names. You can then supply this to your column definition as a parameter for the dropdown, therefore your column definition should look like:

this.ColumnDefs.push({
      headerName: 'Type', field: 'DocumentTypeName', hide: false, editable: true, cellEditor: 'agSelectCellEditor',
      cellEditorParams: {
        values: this.DocumentTypesForDropDown
      }
    });

Another problem you may be experiencing is the dropdown won't show anything; this is because you must have your values for your dropdown defined before you create the column definitions; the cellEditorParams do not take dynamic parameters.

Moving on, in your code, you are setting the column definitions in 2 places: in the setGridOptions() method and in the getDocumentUploadDetails() method.

What I'd suggest is to remove the setting of the column definitions in the setGridOptions() and getDocumentUploadDetails() method and set them in ngOnInit() instead.

I also created a simplified StackBlitz of your code which should help to understand my answer better.