-
-
Notifications
You must be signed in to change notification settings - Fork 19
Row Detail
- Usage
- Changing Addon Options Dynamically
- Calling Addon Methods Dynamically
- Row Detail - Preload View/ViewModel - Loading Spinner
- Row Detail - ViewModel
- Access Parent Component (grid) from the Child Component (row detail)
- Troubleshooting
A Row Detail allows you to open a detail panel which can contain extra and/or more detailed information about a row. For example, we have a user list but we want to display detailed information about this user (his full address, account info, last purchasers, ...) but we don't want to display this in the user grid (for performance and real estate reasons), so a Row Detail is perfect for this.
<aurelia-slickgrid
grid-id="gridId"
column-definitions.bind="columnDefs"
grid-options.bind="gridOptions"
dataset.bind="myDataset"
on-aurelia-grid-created.delegate="aureliaGridReady($event.detail)">
</aurelia-slickgrid>
import { AureliaGridInstance, GridState } from 'aurelia-slickgrid';
export class GridExample {
aureliaGrid: AureliaGridInstance;
aureliaGridReady(aureliaGrid: AureliaGridInstance) {
this.aureliaGrid = aureliaGrid;
}
attached() {
this.defineGrid();
}
/* Define grid Options and Columns */
defineGrid() {
this.columnDefinitions = [ /*...*/ ];
this.gridOptions = {
enableRowDetailView: true,
rowSelectionOptions: {
selectActiveRow: true
},
rowDetailView: {
// We can load the "process" asynchronously in 3 different ways (aurelia-http-client, aurelia-fetch-client OR even Promise)
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 Template
preloadView: PLATFORM.moduleName('examples/preload.html'),
// ViewModel Template to load when row detail data is ready
viewModel: PLATFORM.moduleName('examples/detail-view'),
// Optionally pass your Parent Component reference to your Child Component (row detail component)
parent: this
}
};
}
}
Row Detail is an addon (commonly known as a plugin and are opt-in addon), because this is not built-in SlickGrid and instead are opt-in, we need to get the instance of that addon object. Once we have the instance, we can use getOptions
and setOptions
to get/set any of the addon options, for the list of options available you can see them directly in the addon row detail on the 6pac/SlickGrid
repo.
- Dynamically change the Detail View Row Count (how many grid rows do we want to use for the row detail panel)
changeDetailViewRowCount() {
if (this.aureliaGrid && this.aureliaGrid.extensionService) {
const rowDetailInstance = this.aureliaGrid.extensionService.getExtensionInstanceByName(ExtensionName.rowDetailView);
const options = rowDetailInstance.getOptions();
options.panelRows = this.detailViewRowCount; // change number of rows dynamically
rowDetailInstance.setOptions(options);
}
}
Same as previous paragraph, after we get the SlickGrid addon instance, we can call any of the addon methods, for the complete list of methods available you can refer to the addon Row Detail on the 6pac/SlickGrid
repo.
- Dynamically close all Row Detail Panels
closeAllRowDetail() {
if (this.aureliaGrid && this.aureliaGrid.extensionService) {
const rowDetailInstance = this.aureliaGrid.extensionService.getExtensionInstanceByName(ExtensionName.rowDetailView);
rowDetailInstance.collapseAll();
}
}
- Dynamically close a single Row Detail by it's grid index
This requires a bit more work, you can call the method
collapseDetailView(item)
but it requires to pass the row item object (data context) and it feasible but it's just more work as can be seen below.
closeRowDetail(gridRowIndex: number) {
if (this.aureliaGrid && this.aureliaGrid.extensionService) {
const rowDetailInstance = this.aureliaGrid.extensionService.getExtensionInstanceByName(ExtensionName.rowDetailView);
const item = this.aureliaGrid.gridService.getDataItemByRowIndex(gridRowIndex);
rowDetailInstance.collapseDetailView(item);
}
}
Most of the time we would get data asynchronously, during that time we can show a loading spinner to the user via the preloadView
grid option.
<template>
<h4><i class="fa fa-refresh fa-spin fa-2x fa-fw"></i>Loading...</h4>
</template>
this.gridOptions = {
enableRowDetailView: true,
rowDetailView: {
// ... row detail options
// Preload View Component
preloadComponent: RowDetailPreloadComponent,
}
};
Same concept as the preload, we pass an Aurelia ViewModel to the viewModel
that will be used to render our Row Detail.
this.gridOptions = {
enableRowDetailView: true,
rowDetailView: {
// ... row detail options
// View Component to load when row detail data is ready
viewComponent: RowDetailViewComponent,
}
};
<template>
<div class="container-fluid">
<h2>${model.title}</h2>
<div class="row">
<div class="col-xs-3"><label>Assignee:</label> <input class="form-control" value.bind="model.assignee" /></div>
<div class="col-xs-3"><label>Reporter:</label> <span>${model.reporter}</span></div>
<div class="col-xs-2"><label>Duration:</label> <span>${model.duration}</span></div>
<div class="col-xs-2"><label>% Complete:</label> <span>${model.percentComplete}</span></div>
</div>
<div class="row">
<div class="col-xs-3"><label>Start:</label> <span>${model.start | dateFormat: 'YYYY-MM-DD'}</span></div>
<div class="col-xs-3"><label>Finish:</label> <span>${model.finish | dateFormat: 'YYYY-MM-DD'}</span></div>
<div class="col-xs-2"><label>Effort Driven:</label> <i class.bind="model.effortDriven ? 'fa fa-check' : ''"></i></div>
</div>
<hr>
<h4>
Find out who is the Assignee
<small>
<button class="btn btn-primary btn-sm" click.delegate="alertAssignee(model.assignee)">Click Me</button>
</small>
</h4>
</div>
</template>
import { bindable } from 'aurelia-framework';
export class DetailViewCustomElement {
@bindable() model: {
duration: Date;
percentComplete: number;
reporter: string;
start: Date;
finish: Date;
effortDriven: boolean;
assignee: string; title: string;
};
bind(bindingContext, overrideContext) {
if (bindingContext.model) {
this.model = bindingContext.model;
} else if (overrideContext && overrideContext.bindingContext && overrideContext.bindingContext.model) {
this.model = overrideContext.bindingContext.model;
} else if (overrideContext && overrideContext.parentOverrideContext && overrideContext.parentOverrideContext.bindingContext && overrideContext.parentOverrideContext.bindingContext.model) {
this.model = overrideContext.parentOverrideContext.bindingContext.model;
}
}
alertAssignee(name: string) {
if (typeof name === 'string') {
alert(`Assignee on this task is: ${name.toUpperCase()}`);
} else {
alert('No one is assigned to this task.');
}
}
}
The Row Detail provides you access to the following references (SlickGrid, DataView, Parent Component and the Addon (3rd party plugin)), however please note that all of these references are available from the start except the Parent Component instance, for that one you need to reference it inside your Row Detail Grid Options like so:
// Parent Component (grid)
this.gridOptions = {
enableRowDetailView: true,
rowDetailView: {
// ...
// ViewModel Template to load when row detail data is ready
viewModel: PLATFORM.moduleName('examples/slickgrid/example19-detail-view'),
// Optionally pass your Parent Component reference to your Child Component (row detail component)
parent: this // <-- THIS REFERENCE
}
// a Parent Method that we want to access
showFlashMessage(message: string, alertType = 'info') {
this.message = message;
this.flashAlertType = alertType;
}
}
Then in our Child Component, we can do some action on the Grid, the DataView or even call a method form the Parent Component (the showFlashMessage
in our demo), with that in mind, here is the code of the Child Component
<div class="container-fluid">
<h3>${model.title}</h3>
<-- delete a row using the DataView & SlickGrid objects -->
<button class="btn btn-primary btn-danger btn-sm" click.delegate="deleteRow(model)" data-test="delete-btn">
Delete Row
</button>
<!-- calling a Parent Component method -->
<button class="btn btn-default btn-sm" click.delegate="callParentMethod(model)" data-test="parent-btn">
Call Parent Method
</button>
</div>
import { GridRowDetailComponent } from './grid-rowdetail.component';
export class DetailViewCustomElement{
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: GridRowDetail;
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);
// and perhaps display a flash message by calling a method on the Parent Component
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}`);
}
}
The reason is because the Row Selection (checkbox) plugin is a special column and Aurelia-Slickgrid is adding an extra column dynamically for the Row Selection checkbox and that is not reflected in your local copy of columnDefinitions
. To address this issue, you need to get the Aurelia-Slickgrid internal copy of all columns (including the extra columns), you can get it via getAllColumnDefinitions()
from the Grid Service and then you can use to that array and that will work.
<aurelia-slickgrid grid-id="grid16"
column-definitions.bind="columnDefinitions"
grid-options.bind="gridOptions"
dataset.bind="dataset"
on-aurelia-grid-created.delegate="aureliaGridReady($event.detail)">
</aurelia-slickgrid>
aureliaGridReady(aureliaGrid: AureliaGridInstance) {
this.aureliaGrid = aureliaGrid;
}
addNewColumn() {
const newColumn = { /*...*/ };
const allColumns = this.aureliaGrid.gridService.getAllColumnDefinitions();
allColumns.push(newColumn);
this.columnDefinitions = allColumns.slice(); // or use spread operator [...cols]
// you could also use SlickGrid setColumns() method
// this.aureliaGrid.slickGrid.setColumns(cols);
}
Contents
- Aurelia-Slickgrid Wiki
- Installation
- Styling
- Interfaces/Models
- Testing Patterns
- Column Functionalities
- Global Grid Options
- Localization
- Events
- Grid Functionalities
- Auto-Resize / Resizer Service
- Resize by Cell Content
- Add/Delete/Update or Highlight item
- Dynamically Change Row CSS Classes
- Column Picker
- Composite Editor Modal
- Context Menu
- Custom Tooltip
- Excel Copy Buffer
- Export to Excel
- Export to File (CSV/Txt)
- Grid Menu
- Grid State & Presets
- Grouping & Aggregators
- Header Menu & Header Buttons
- Header Title Grouping
- Pinning (frozen) of Columns/Rows
- Row Colspan
- Row Detail
- Row Selection
- Tree Data Grid
- SlickGrid & DataView objects
- Addons (controls/plugins)
- Backend Services