0
votes

I am using Angular SlickGrid as parent component and plugin Detail-View as child component. In Detail-View component I'm using few buttons for specific tasks. One of them is button Delete. The issue is when the button is clicked, it triggers components service to delete selected row from the grid by it's ID. Back-end works perfectly. BUT! On the front-end side that row is still visible, unless I reload the page manually. And I need that row from parent component would be deleted on click. I tried to use EventEmitters but aperently SlickGrid doesn't recognizing this functionality. If everything would be in one component, I could ease use: this.angularGrid.gridService.deleteItemById(del_id); but since detail-view data is passed by rowDetailView in this.gridOptions there is no component template tagging like <app-row-detail-view></app-row-detail-view>

My Detail-View Component (child):

  @Input() del_id: string;
  @Output() onDelete = new EventEmitter<string>();

  model: {
    id: string;
    domains: string;
    example_site: string;
    status: string;
    created: string;
    image: string;
  };

  deleteRecipe() {
    if (confirm('Are You sure?')) {
      console.log("EVENT 1");
      this.del_id = this.model.id;
      this.onDelete.emit(this.del_id);
      console.log(this.del_id);
      return this.recipeService.removeRecipe(this.del_id)
      .subscribe(u => {
        return u;
      });
    }
  }

My Detail-View HTML(child):

<button (click)="deleteRecipe()">DELETE</button>

My PARENT component HTML:

<angular-slickgrid
      gridId="grid11"
      [columnDefinitions]="columnDefinitions"
      [gridOptions]="gridOptions"
      [gridWidth]=1500
      [dataset]="dataset"
      (onAngularGridCreated)="angularGridReady($event)"
      (onDelete)="onDeleted($event)"
      >
</angular-slickgrid>

and i can't use here something like [del_id]="del_id" cuz i get big error in the console..

My Parent component .ts:

  onDeleted(del_id: string) {
    console.log("EVENT 2");
    console.log(del_id);
    this.angularGrid.gridService.deleteItemById(del_id);
  }

  this.gridOptions = {
      enableAsyncPostRender: true,
      enableFiltering: true,
      enableAutoResize: true,
      enableCellNavigation: true,
      enableGrouping: false,
      enableRowDetailView: true,
      enableColumnReorder: false,
      rowSelectionOptions: {
        selectActiveRow: true
      },
      rowDetailView: {
        process: (item: any) => this.simulateServerAsyncCall(item),
        viewComponent: RecipeDetailsComponent,
        loadOnce: true,
        singleRowExpand: true,
        useRowClick: true,
        panelRows: this.detailViewRowCount
      }
    };

  simulateServerAsyncCall(item: any) {
    return new Promise((resolve) => {
      const itemDetail = item;
      resolve(itemDetail);
    });
  }

I have tried a lot of articles about EventEmitters, like: https://github.com/6pac/SlickGrid/blob/master/plugins/slick.rowdetailview.js#L10, https://www.infragistics.com/community/blogs/b/infragistics/posts/understanding-output-and-eventemitter-in-angular, https://github.com/ghiscoding/Angular-Slickgrid/blob/master/src/app/modules/angular-slickgrid/models/rowDetailView.interface.ts.

Any help would be very appreciated! Thank You in advance dear colleagues!

1
I'm guessing that you're thinking too much the Angular way, just close the row detail after you click the delete button but before you call the deleteItemById. There's a demo in the Row Detail - Wiki. Just as a reminder, this lib is a wrapper of a jQuery lib, which is why I said you're thinking too much the Angular way. You could also look at the new Cell Menu extension that I've added, it's perfect for Action buttons.ghiscoding
To extend on my previous comment, another person opened a similar issue on my other lib Aurelia-Slickgrid, I support both and they use roughly the same code, anyway his issue was with Row Detail and Pagination (OData) and it was exactly like I said in my previous post, just close the Row Detail and it should work... you can take a look at that issue and compare (it's Aurelia code but it's very similar)ghiscoding
I get what you saying and thank you for replying, but delete button is in child coimponent. How to pass a "signal" to parent slickgrid that he knows what row to delete.. ?Aš Vaidas
in our project we made a detail view as a sidebar, when we click on a row it opens this sidebar and when we do certain button action click we update the parent grid. The only we've done to get this working is to pass the parent grid object with something like [angularGridParentList]="angularGrid" and then in the child component I simply use that angularGrid reference (with @Input() angularGridParentList: AngularGridInstance;) to call a row re-render or delete from the parent grid and that's it.ghiscoding
... I don't think you need any eventEmitter or Output. I'm quite sure you can do exactly that in your use case to get it to work.... so in your child you would call this.angularGridParentList.deleteItemById(yourId) and that's it, there's no event or anything, just a reference to the parent grid instanceghiscoding

1 Answers

1
votes

Please note that I'm the author of Angular-Slickgrid.

I agree that it was challenging to do this in prior version, so to deal with this I added new references to the SlickGrid, DataView references and also Parent Component instance to the Row Detail extension, so you can now access all of these new references into your Child Component. To get advantage of these new changes, please update to the latest Angular-Slickgrid version 2.16.x.

Now with these references you can take advantage of them and change your Row Detail Child Component to the following

You can see a live demo of your question (how to delete a row from the Child Component) in the updated Row Detail Example and I have also updated the Row Detail Wiki

Child Component - Row Detail View

<div class="container-fluid">
  <h3>{{model?.title}}</h3>

    <button class="btn btn-primary btn-danger btn-sm" (click)="deleteRow(model)" data-test="delete-btn">
      Delete Row
    </button>
    <button class="btn btn-default btn-sm" (click)="callParentMethod(model)" data-test="parent-btn">
      Call Parent Method
    </button>
</div>

Child Component - Row Detail Component

import { Component } from '@angular/core';
import { GridRowDetailComponent } from './grid-rowdetail.component';

@Component({
  templateUrl: './rowdetail-view.component.html'
})
export class RowDetailViewComponent {
  model: {
    duration: Date;
    percentComplete: number;
    reporter: string;
    start: Date;
    finish: Date;
    effortDriven: boolean;
    assignee: string;
    title: string;
  };

  // you also have access to the following objects (it must match the exact property names shown below)
  addon: any; // row detail addon instance
  grid: any;
  dataView: any;

  // you can also optionally use the Parent Component reference
  // NOTE that you MUST provide it through the "parent" property in your "rowDetail" grid options
  parent: GridRowDetailComponent;

  constructor() { }

  alertAssignee(name: string) {
    if (typeof name === 'string') {
      alert(`Assignee on this task is: ${name.toUpperCase()}`);
    } else {
      alert('No one is assigned to this task.');
    }
  }

  deleteRow(model) {
    if (confirm(`Are you sure that you want to delete ${model.title}?`)) {
      // you first need to collapse all rows (via the 3rd party addon instance)
      this.addon.collapseAll();

      // then you can delete the item from the dataView
      this.dataView.deleteItem(model.id);

      this.parent.showFlashMessage(`Deleted row with ${model.title}`, 'danger');
    }
  }

  callParentMethod(model) {
    this.parent.showFlashMessage(`We just called Parent Method from the Row Detail Child Component on ${model.title}`);
  }
}
<div class="container-fluid">
  <h2>{{title}}</h2>
  <div class="subtitle" [innerHTML]="subTitle"></div>

  <div class="alert alert-{{flashAlertType}} col-sm-6" *ngIf="message" data-test="flash-msg">{{message}}</div>

  <hr />

  <angular-slickgrid gridId="grid21" [columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions"
    [dataset]="dataset" (onAngularGridCreated)="angularGridReady($event)">
  </angular-slickgrid>
</div>
import { Component, OnInit } from '@angular/core';
import {
  AngularGridInstance,
  Column,
  ExtensionName,
  FieldType,
  Filters,
  Formatters,
  GridOption
} from './../modules/angular-slickgrid';
import { RowDetailViewComponent } from './rowdetail-view.component';
import { RowDetailPreloadComponent } from './rowdetail-preload.component';


@Component({
  templateUrl: './grid-rowdetail.component.html'
})
export class GridRowDetailComponent implements OnInit {
  angularGrid: AngularGridInstance;
  columnDefinitions: Column[];
  gridOptions: GridOption;
  dataset: any[];
  detailViewRowCount = 9;
  message: string;
  flashAlertType = 'info';

  constructor() { }

  angularGridReady(angularGrid: AngularGridInstance) {
    this.angularGrid = angularGrid;
  }

  get rowDetailInstance(): any {
    return this.angularGrid && this.angularGrid.extensionService.getSlickgridAddonInstance(ExtensionName.rowDetailView) || {};
  }

  ngOnInit(): void {
    this.defineGrid();
  }

  /* Define grid Options and Columns */
  defineGrid() {
    this.columnDefinitions = [ /** ... */ ];

    this.gridOptions = {
      autoResize: {
        containerId: 'demo-container',
        sidePadding: 15
      },
      enableFiltering: true,
      enableRowDetailView: true,
      rowSelectionOptions: {
        selectActiveRow: true
      },
      rowDetailView: {
        // We can load the "process" asynchronously in 2 different ways (httpClient OR even Promise)
        process: (item) => this.simulateServerAsyncCall(item),
        // process: (item) => this.http.get(`api/item/${item.id}`),

        // load only once and reuse the same item detail without calling process method
        loadOnce: true,

        // limit expanded row to only 1 at a time
        singleRowExpand: false,

        // false by default, clicking anywhere on the row will open the detail view
        // when set to false, only the "+" icon would open the row detail
        // if you use editor or cell navigation you would want this flag set to false (default)
        useRowClick: true,

        // how many grid rows do we want to use for the row detail panel (this is only set once and will be used for all row detail)
        // also note that the detail view adds an extra 1 row for padding purposes
        // so if you choose 4 panelRows, the display will in fact use 5 rows
        panelRows: this.detailViewRowCount,

        // you can override the logic for showing (or not) the expand icon
        // for example, display the expand icon only on every 2nd row
        // expandableOverride: (row: number, dataContext: any, grid: any) => (dataContext.id % 2 === 1),

        // Preload View Component
        preloadComponent: RowDetailPreloadComponent,

        // View Component to load when row detail data is ready
        viewComponent: RowDetailViewComponent,

        // Optionally pass your Parent Component reference to your Child Component (row detail component)
        parent: this
      }
    };

    this.getData();
  }


  closeAllRowDetail() {
    if (this.angularGrid && this.angularGrid.extensionService) {
      this.rowDetailInstance.collapseAll();
    }
  }

  showFlashMessage(message: string, alertType = 'info') {
    this.message = message;
    this.flashAlertType = alertType;
  }

}