Flex Grid Master- Detail (Nested Grid Question)

Posted by: kapil.r.shah on 1 July 2019, 11:17 pm EST

  • Posted 1 July 2019, 11:17 pm EST

    Hello,
    Hello,
    I am using Angular 7 . Installed Angular CLI and created a new app . Working on NestedGrids(RowDetail) sample .

    https://www.grapecity.com/wijmo/demos/Grid/Master-Detail/NestedGrids(RowDetail)/angular

    I see that in app.Component.ts , the categories and product data is already loaded in the constructor and then filtered in getProducts method

    In my use case , I have child records data which will be large ( around 20,000) so do not want to load all the data in the constructor. I want to make a API call by clicking the wj-glyph-plus icon and make a API call to the server and fetch the child records.

    Do Wijmo have an example of fetching the child records by making an API call to the server.

    I am doing a POC to make a API call and its not working.

    Thanks,
  • Replied 2 July 2019, 6:48 pm EST


    Hello,

    You may use the createDetailCell property of FlexGridDetailProvider class to call you API and load the grid when the data is returned from the server.
    Please refer to the sample attached.FlexGridDetail.zip
  • Replied 2 July 2019, 10:52 pm EST

    Thank you for the sample project. I build the project . Had a compilation error

    ERROR in src/app/app.component.ts(53,22): error TS2339: Property 'style' does not exist on type 'Element'.

    Still , the application works on Chrome Browser and shows the products data .However does not show correctly in IE browser.
  • Replied 3 July 2019, 3:47 am EST


    I see that in the sample attached you are using products and categories which are
    wjcOdata.ODataCollectionView

    In my code , I am using CollectionView . What is the method for addHandler for CollectionView. I tried using this.auditLogDetailsDataCollectionView.collectionChanged.addHandler but it is not working.




    initGrid(grid: wjcGrid.FlexGrid) {
    let self = this;
    new wjcGridDetail.FlexGridDetailProvider(grid, {createDetailCell: function(row) {
    const AuditLogId = row.dataItem.AuditLogId;
    console.log(AuditLogId);
    this.LogDetails$ = self.auditService.getAuditLogDetails(AuditLogId);
    this.LogDetails$.subscribe(data => {
    // console.log(data);
    this.auditLogDetailsDataCollectionView = new CollectionView(data);
    // console.log(this.auditLogDetailsDataCollectionView);
    var cell = wjcCore.createElement(`<div><div>Loading......</div><div style="display: none"></div></div>`);
    var gridChild = new wjcGrid.FlexGrid(cell.children[1], {
    columns: [
    { header: "PropertyName", binding: "PropertyName", width: "*" },
    { header: "OriginalValue", binding: "OriginalValue", width: "*" },
    { header: "NewValue", binding: "NewValue" }

    ],
    headersVisibility: wjcGrid.HeadersVisibility.Column,
    isReadOnly: true,
    autoGenerateColumns: false
    });
    this.auditLogDetailsDataCollectionView.collectionChanged.addHandler(function(s, e) {
    // cell.children[0].style.display = "none";
    gridChild.hostElement.style.display = "block";
    gridChild.itemsSource = s;
    grid.autoSizeRows();
    });
    return cell;
    });

    }//end of row
    });
    }





  • Replied 3 July 2019, 4:48 pm EST

    >> 'style' does not exist

    The children property of an HTML element returns an object of HTMLElement class which does not have a style property. But in our case, the element returned will be an instance of HTMLDivElement which have a style property. But, typescript does not know that because it works at runtime. To solve this issue, we just need to cast the element to a div element.

    var c0 = cell.children[0] as HTMLDivElement;
    c0.style.display = "none";

    >> Does not work in IE


    We just need to invalidate the child grid when it is loaded by calling the invalidate method of FlexGrid.

    >> How to update using CollectionView

    Please refer to the attached sample.

    In the sample, I have changed the DataService class to use CollectionView instead of ODataCollectionView. In this method, I created an empty collectionView object and returned this object. When the data is returned from the server, I just assigned it to the sourceCollection property of the CollectionView.

    In the createDetailCell, I handled the sourceCollectionChanged event of CollectionView instead of loaded event of ODataCollectionView. FlexGridDetail _SAMPLE.zip
  • Replied 4 July 2019, 10:58 pm EST

    What code expands and collapse i.e toggle the FlexGrid detail. I implemented the code as per above. In my case , the toggle does not happen. It does not expand and collapse. The code builds and I do not get any error. I do see that I get the data .

    initGrid(grid: wjcGrid.FlexGrid) {
    const self = this;
    new wjcGridDetail.FlexGridDetailProvider(grid, {createDetailCell: function(row) {
    const AuditLogId = row.dataItem.AuditLogId;
    console.log(AuditLogId);
    this.LogDetails$ = self.auditService.getAuditLogDetails(AuditLogId);
    this.LogDetails$.subscribe(data => {
    // console.log(data);
    this.auditLogDetailsDataCollectionView = new CollectionView(data);
    console.log(this.auditLogDetailsDataCollectionView);
    const cell = wjcCore.createElement(`<div><div>Loading......</div><div style="display: none"></div></div>`);
    const gridChild = new wjcGrid.FlexGrid(cell.children[1], {
    columns: [
    { header: 'PropertyName', binding: 'PropertyName', width: '*' },
    { header: 'OriginalValue', binding: 'OriginalValue', width: '*' },
    { header: 'NewValue', binding: 'NewValue' }

    ],
    headersVisibility: wjcGrid.HeadersVisibility.Column,
    isReadOnly: true,
    autoGenerateColumns: false
    });
    this.auditLogDetailsDataCollectionView.sourceCollectionChanged.addHandler(function(s, e) {
    const c0 = cell.children[0] as HTMLDivElement;
    c0.style.display = 'none';
    gridChild.itemsSource = this.auditLogDetailsDataCollectionView;
    gridChild.hostElement.style.display = 'block';
    grid.autoSizeRows();
    gridChild.invalidate();
    });
    return cell;
    });

    }// end of row
    });
    }

    <wj-flex-grid #flex [(itemsSource)]="auditDataCollectionView" (initialized)="initGrid(flex)" [autoGenerateColumns]=false [isReadOnly]="true" >
    <wj-flex-grid-column [header]="'Log Date'" [binding]="'EventDateUTC'" [width]="250" width="2*"></wj-flex-grid-column>
    <wj-flex-grid-column [header]="'Activity'" [binding]="'Description'" [wordWrap] = "true" [width]="650" width="2*"></wj-flex-grid-column>
    <wj-flex-grid-column [header]="'Description'" [binding]="'TypeFullName'" [width]="250" width="2*"></wj-flex-grid-column>
    <wj-flex-grid-column [header]="'User'" [binding]="'UserName'" [width]="150" width="2*"></wj-flex-grid-column>
    <wj-flex-grid-column [header]="'Log Action'" [binding]="'Action'" [width]="150" width="2*"></wj-flex-grid-column>

    </wj-flex-grid>
  • Replied 5 July 2019, 1:17 am EST

    I did a console.log on gridChild on your sample project and see that it has property _activeCell: div.wj-cell.wj-state-selected.wj-state-active

    When I did a console.log on gridChild on the my project, I see that it is null
    _activeCell : null

    Is this a css issue ?
    I am getting the correct data but the wj-btn wj-btn-glyph wj-elem-detail icon does not expand and collapse.

    I am loading node_modules/@grapecity/wijmo.styles/wijmo.scss file and I see that you are loading node_modules/@grapecity/wijmo.styles/wijmo.css.

    Thanks



  • Replied 7 July 2019, 6:35 pm EST

    Hi,

    Please refer to the attached sample.

    In this sample, We have updated the code to use Observable like you are using and it works without any issues. Please use the provided sample as a reference and if the issue still persists, please provide us with a sample so we can investigate further.

    >> _activeCell is null

    The null value of _activeCell indicates that there is no currently selected cell in the grid because the itemsSource of the grid is empty.

    >> CSS issue

    We have also updated the sample to use SCSS instead of CSS and there is no issue in the project. SCSS is an extension of CSS and if your project was created with SCSS, then it should work without any issues.

    FlexGridDetail_updated.zip
  • Replied 8 July 2019, 12:32 am EST

    I implemented your sample code and now the code works. Thank you for providing support
  • Replied 8 July 2019, 4:06 am EST

    Question : How do I show the default sort indicators when the FlexGrid loads with data ?

    Currently when the Flex Grid Loads, it does not show any sort indicators. I would like to show the sort indicators to make the user aware that sorting works

    Thanks,
  • Replied 8 July 2019, 10:13 pm EST

    You may apply default sorting by using the sortDescriptions property of CollectionView class. You may simply pass an array of string with property names on which sorting should be applied:

    self.products = new wjcCore.CollectionView([], {
    filter: function(item, prop) {
    return item.CategoryID == catId;
    },
    sortDescriptions: ['ProductName']
    });


    You could also pass a SortDescription object to the sortDescriptions property:

    constructor(private dataSvc: DataService) {
    this.categories = this.dataSvc.getCategories();
    this.categories.sortDescriptions.push(new wjcCore.SortDescription('CategoryName', true));
    }


    You could also simply sort the grid by clicking on the column header of the column by which you wish to sort the grid.

    When sorting is applied on the grid, you may see an arrow glyph icon on the column header on which the sorting is applied.

    You may also refer to the updated sample attached. Please let us know if this is your requirement.

    API Reference:
    • SortDescription class: https://www.grapecity.com/wijmo/api/classes/wijmo.sortdescription.html

    • sortDescriptions property: https://www.grapecity.com/wijmo/api/classes/wijmo.collectionview.html#sortdescriptions


    FlexGridDetail.zip
  • Replied 9 July 2019, 12:44 am EST

    Yes the Sorting Example helps. I am able to use to show the default sort for the column


    this.categories.sortDescriptions.push(new wjcCore.SortDescription('CategoryName', true));
    }


    Thank you for providing support.
  • Replied 9 July 2019, 4:14 am EST



    I see that the sorting does not sort the date correctly. Please see screen shot . I am trying to sort date in descending order.

    this.auditDataCollectionView.sortDescriptions.push(new wjcCore.SortDescription('EventDateUTC', false));



  • Replied 9 July 2019, 4:21 am EST

    Also , I am also interested in printing out the flexgrid as pdf, along with Master and its Details i.e parent and child rows. Does Wijmo support that feature.

    Thanks
  • Replied 9 July 2019, 9:42 pm EST

    Hi again,

    1. The date is not sorted correctly

    We are sorry but we were not able to replicate the issue at our end. Please refer to the sample attached and let us know whether we are missing something to replicate the issue. Also, could you please try using the sortComparer property of CollectionView class to sort the dates as shown in the code snippet below:

    this.auditDataCollectionView.sortComparer = function(a, b) {
    if(wjcCore.isDate(a) && wjcCore.isDate(b)) {
    return a.valueOf() - b.valueOf();
    }
    return null;
    }


    Please let us know if this solves your issue.

    2. Export to PDF

    We have asked the dev team on how to export the FlexGrid with all the row details. We will give you an update as soon as we have any further information.

    FlexGridDetails_using_observable_updated.zip
  • Replied 10 July 2019, 5:31 am EST

    In my code , I am converting into CollectionView First and then looping through it to convert it to date. After that I am sorting it.

    Here formatDate is imported from
    import { formatDate } from '@angular/common';

    In your code, I see that you are first converting to Date and then converting the data to collection and then sorting it

    Is that creating a problem. Also if you see the screen shot attached, I am having problem with date having time between 07/09/2019 12:35:04 PM and 07/09/2019 12:47:06 PM



    Thanks



    this.auditSearchResults$.subscribe(data => {
    this.auditDataCollectionView = new wjcCore.CollectionView(data);

    this.auditDataCollectionLength = this.auditDataCollectionView._view.length;
    // Convert to Date
    for (let i = 0; i < this.auditDataCollectionView.items.length; i++) {
    const item = this.auditDataCollectionView.items[i];

    const dt = new Date(item.EventDateUTC);
    item.EventDateUTC = formatDate(dt, 'MM/dd/yyyy h:mm:ss a', 'en-US');
    }
    this.auditDataCollectionView.sortDescriptions.push(new wjcCore.SortDescription('EventDateUTC', false));
    // Set Page Size
    this.auditDataCollectionView.pageSize = 50;
    // return this.auditDataCollectionView;
    });
  • Replied 10 July 2019, 5:33 am EST

    If I comment out , then the dates do show correctly in descending order.
    ;

    this.auditDataCollectionView.sortDescriptions.push(new wjcCore.SortDescription('EventDateUTC', false))
  • Replied 10 July 2019, 9:30 pm EST

    Hi,

    The reason for the date not sorting correctly maybe because the date is the converted to string in your code using the formatDate method. Due to this, when sorting is applied, the column is sorted according to the String data type instead of the Date data type.
    To solve this issue, instead of converting the date to a string , I would suggest using the format property of Column class to format the date in the grid. Please refer to the sample that I provided earlier.

    >> Commenting out the line works

    Removing the sort description line from the code as the data is already sorted according to date before being loaded into the grid.
  • Marked as Answer

    Replied 10 July 2019, 9:55 pm EST

    >> Export grid to PDF

    You may use the export method of FlexGridPdfConverter to export the grid to PDF. To also include the row details, you may set the drawDetailRows and customCellContent to true and use the formatItem callback to draw the detail cells. Please refer to the sample attached.

    PS: Only the visible row details will be exported to the PDF because when a row detail is not visible, the HTML element containing the detail row is also not visible in the DOM. Therefore, the PDF converter will not be able to render it.

    API Reference:



    FlexGridDetails_export.zip
  • Replied 17 October 2019, 3:52 am EST

    In the nested grid, what is the property for word wrap. The text inside the grid is around 4000 characters



    const cell = wjcCore.createElement(`<div>
    <div>Loading......</div>
    <div style="display: none"></div>
    </div>`);
    const gridChild = new wjcGrid.FlexGrid(cell.children[1], {
    columns: [
    { header: 'Property Name', binding: 'PropertyName', width: '*' },
    { header: 'Before Edit', binding: 'OriginalValue', width: '3*' },
    { header: 'After Edit', binding: 'NewValue', width: '3*' }
    ],
    headersVisibility: wjcGrid.HeadersVisibility.Column,
    isReadOnly: true,
    autoGenerateColumns: false
    });




  • Replied 17 October 2019, 5:31 pm EST

    Hi Kapil,

    Could you please try using the wordWrap and the multiLine property of the Column class?
    columns: [
    { header: 'Property Name', binding: 'PropertyName', width: '*' },
    { header: 'Before Edit', binding: 'OriginalValue', width: '3*', wordWrap: true, multiLine: true },
    { header: 'After Edit', binding: 'NewValue', width: '3*', wordWrap: true, multiLine: true }
    ]

    Let me know if this solves your issue.

    ~regards
  • Replied 17 October 2019, 11:39 pm EST

    It did not solve the issue. In fact it truncated the test. My text was

    Remove/Restore Email Template
    ,View Document List,Edit Document,Edit Email Template
    ,View Email Template List,Remove/Restore Document,Create Email Template
    ,Create Document,02. Approve OSEC Approval,12. Finalize NV,Create Email,Remove/Restore Vote Template,Edit Quorum Rule
    ,Edit Governor Profile
    ,View Vote Option List
    ,11. Notify Vote Tally,01. Admin,04. Active Users,View Implemenation Template List
    ,Create Governor Profile
    ,03. Notify vote,View OSEC Governors Portal,Remove/Restore Quorum Rule
    ,02. Approve OSEC Approval Mobile,Remove/Restore Lookup Data,Edit Emails,05. Activity Log,Remove/Restore Governor Profile
    ,08. Notify NV for Distribution List Approval,Edit Implemention Template,View Emails,Remove/Restore Emails,View NV Distribution,Create Implementation Template,02. Role-Group Managment,Edit Lookup Data,07. Notify NV for Governor Actions,View Quorum Rule
    List,02. View Governor Mobile,View Lookup Data List,02. Submit vote ,01. View Governor Portal,Create Vote Template,Migrate,03. Create NV,View Access Denied,04. Notify vote Govenror Mobile,04. Edit NV,View Governor Profile
    List,Remove/Restore Vote Option,Create Lookup Data,Edit Vote Template,01. View Governor NV,Create Vote Option,Edit Vote Option,View Vote Template List,Remove/Restore Implementation Template,Create Quorum Rule
    ,View OSEC Portal,03. Submit vote Governor Mobile

    and it showed only Remove/Restore Email Template

    Please advice
    Kapil
  • Replied 20 October 2019, 10:08 am EST

    I have a bug in my master detail grid i.e NestedGrids(RowDetail)

    Sometimes whenever I click the icon to show the child rows, the code breaks.

    TypeError: Cannot read property 'style' of null
    gridChild.hostElement.style.display = 'block';


    Does gridChild has a property of style???



    initGrid(grid: wjcGrid.FlexGrid) {
    const self = this;
    grid.autoSizeRows(0, grid.rows.length - 1, false, 20);
    // tslint:disable-next-line:no-unused-expression
    new wjcGridDetail.FlexGridDetailProvider(grid, {
    createDetailCell: function(row) {
    const AuditLogId = row.dataItem.AuditLogId;
    console.log(AuditLogId);

    // filtering is done here because the api returns all the data
    self.auditLogDetailsDataCollectionView = new wjcCore.CollectionView(
    [],
    {
    filter: function(item, prop) {
    return item.AuditLogId === AuditLogId;
    }
    }
    );
    // self.LogDetails$ = self.auditService.getAuditLogDetails(AuditLogId);
    self.store.dispatch(new fromStore.LoadAuditLogDetails(AuditLogId));
    self.LogDetails$ = self.store.select(fromStore.getAuditLogDetail);
    self.LogDetails$.subscribe(data => {
    console.log(data);
    self.auditLogDetailsDataCollectionView.sourceCollection = data;
    });

    // First div is to show the user that data is loading
    // Second is to create the grid
    const cell = wjcCore.createElement(`<div>
    <div>Loading......</div>
    <div style="display: none"></div>
    </div>`);
    const gridChild = new wjcGrid.FlexGrid(cell.children[1], {
    columns: [
    { header: 'Property Name', binding: 'PropertyName', width: '*' },
    { header: 'Before Edit', binding: 'OriginalValue', width: '3*' },
    { header: 'After Edit', binding: 'NewValue', width: '3*' }
    ],
    headersVisibility: wjcGrid.HeadersVisibility.Column,
    isReadOnly: true,
    autoGenerateColumns: false
    });

    self.auditLogDetailsDataCollectionView.sourceCollectionChanged.addHandler(
    function(s, e) {
    const c0 = cell.children[0] as HTMLDivElement;
    c0.style.display = 'none';
    gridChild.itemsSource = self.auditLogDetailsDataCollectionView;
    gridChild.hostElement.style.display = 'block';
    grid.autoSizeRows(0, grid.rows.length - 1, false, 20);
    gridChild.invalidate();

    }
    );
    // console.log('K2', gridChild);
    return cell;
    },
    rowHasDetail: function(row) {
    return (
    row.dataItem.Action === 'Update' &&
    row.dataItem.AuditLogDetails.length > 0
    );
    }
    });
    }


  • Replied 20 October 2019, 5:23 pm EST

    Hi Kapil,

    Regarding word-wrap:

    The reason that your data is not visible is that the height of the row is small to show all of the data that is wrapped in the next lines. To show the wrapped data, you may simply set the height of the row to a large value.
    gridChild.rows[0].size = 200; // set the size of the row

    I would also suggest you to set the value of allowResizing property of FlexGrid to 'Both' to allow resizing of the row also.

    Regarding the error:

    Could you please try adding a condition to check whether the child FlexGrid is created and then change its properties:
    if (gridChild instanceof wjcGrid.FlexGrid && gridChild.hostElement) {
    gridChild.itemsSource = self.products;
    gridChild.hostElement.style.display = "block";
    grid.autoSizeRows();
    gridChild.invalidate();
    gridChild.rows[0].size = 200; // set the size of the row
    }

    If the issue still exists, could you please modify the sample attached so that it replicates the issue.

    ~regards

    FlexGridDetail.zip
  • Replied 21 October 2019, 1:29 am EST

    Hi Ashwin,
    Thanks for your help. The error looks fixed and
    the gridChild.rows[0].size = 200; seems to be working.

    Where do I set the value of allowResizing property of FlexGrid to 'Both' to allow resizing of the row also.

    Thanks,
  • Replied 21 October 2019, 3:19 pm EST

    Hi Kapil,

    You could set the allowResizing property when you are creating the child FlexGrid:
    var gridChild = new wjcGrid.FlexGrid(cell.children[1], {
    columns: [
    { header: "Name", binding: "ProductName", width: "*" },
    {
    header: "Oty/Unit",
    binding: "QuantityPerUnit",
    width: "*",
    wordWrap: true,
    multiLine: true
    },
    { header: "Unit Price", binding: "UnitPrice" },
    { header: "Discontinued", binding: "Discontinued" }
    ],
    headersVisibility: wjcGrid.HeadersVisibility.All,
    isReadOnly: true,
    autoGenerateColumns: false,
    allowResizing: "Both" // allow resizing of both rows and columns
    });

    ~regards
Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels