Angular-Slickgrid

repository·master·Indexed 19 days ago

https://github.com/ghiscoding/angular-slickgrid

An Angular wrapper for SlickGrid, a high-performance JavaScript data grid capable of handling millions of rows. It provides an Angular-friendly implementation of SlickGrid-Universal features, including support for multiple styling themes (Default, Bootstrap, Material, Salesforce), custom backend services, and GraphQL integration for pagination, filtering, and sorting.

Tokens
122.3K
Snippets
345
Records
429
Agent score
63%

What's inside angular-slickgrid

  1. What is the Composite Editor Modal?

    master

    The Composite Editor Modal is a feature that allows users to perform bulk or individual actions—such as creating, cloning, editing, or mass updating rows—through a single composed form.

    Instead of editing cells individually, the modal loops through the editor definitions of all specified columns and displays them as a single unified form. The labels for the form inputs are pulled directly from the column definitions.

    Available CompositeEditorModalType values:

    • create: Creates a new row/item (requires enableAddRow: true).
    • clone: Copies an existing row and allows edits before saving (requires enableAddRow: true).
    • edit: Edits an existing row/item.
    • mass-update: Applies changes to the entire dataset.
    • mass-selection: Applies changes only to the currently selected rows.
    • auto-mass: Automatically detects whether to perform a mass-update (if no rows are selected) or a mass-selection (if rows are selected).
  2. Sort complex objects using dot notation

    master

    You can sort by properties nested within objects by using dot (.) notation in the field property of your column definition. The grid will automatically traverse the object path to find the value.

    // If dataset is: { buyer: { address: { zip: 123456 } } }
    this.columnDefinitions = [
      {
        id: 'zip', 
        name: 'Zip Code', 
        field: 'buyer.address.zip', 
        sortable: true
      }
    ];
  3. Understand Grid State vs. Presets

    master

    Angular-Slickgrid distinguishes between the current live state of a grid and predefined configurations called presets.

    • Grid State: Represents the currently active configuration of the grid, including Columns (size, position, visibility), Filters, Sorters, and Pagination (pagination is only available when using a Backend Service API).
    • Presets: A way to pre-configure a grid with specific Columns, Filters, Sorters, or Pagination. Presets are useful for loading a specific view (e.g., hiding certain columns or applying default filters) when the grid is initialized.

    Priority Logic: When loading a grid, the following priority order is applied:

    1. Presets: If presets are provided, they take precedence.
    2. Filter SearchTerms: If no presets exist, the grid uses searchTerms defined in the column definitions.
    3. Defaults: If neither are present, the grid loads with default column and grid definitions.
  4. Access Grid and Parent references from Row Detail components

    master

    When a viewComponent is rendered as a row detail, it automatically has access to several key objects. To access your own parent component, you must explicitly pass it via the parent property in the rowDetailView configuration.

    Available properties in the Row Detail component:

    • model: The data object loaded for the detail view.
    • addon: The Row Detail addon instance (allows calling collapseAll(), etc.).
    • grid: The SlickGrid instance.
    • dataView: The DataView instance (allows row manipulation like deleteItem()).
    • parent: The reference to your parent component (only if provided in rowDetailView.parent).
    // Inside the Row Detail View Component
    export class RowDetailViewComponent {
      model: any;      // The loaded data
      addon: any;      // The row detail addon
      grid: any;       // SlickGrid instance
      dataView: any;  // DataView instance
      parent: any;    // Your custom parent component
    
      deleteRow(model) {
        this.addon.collapseAll(); // Use addon to close panels
        this.dataView.deleteItem(model.id); // Use dataView to remove data
        this.parent.showFlashMessage('Deleted!'); // Use parent to call custom methods
      }
    }
  5. Understand the property lookup order

    master

    When the grid determines a property value (like cssClasses or formatter), it follows a specific hierarchy. The first level that defines the property wins:

    1. Row-level item metadata (from getItemMetadata)
    2. Column-level item metadata by column id
    3. Column-level item metadata by column index
    4. Column definition (the column configuration object)
    5. Grid options
    6. Grid defaults
  6. Pre-filter and Pre-sort Select Filter Collections

    master

    You can control which items appear in the dropdown using collectionFilterBy and collectionSortBy.

    Supported Operators for collectionFilterBy:

    • equal: Matches the provided value.
    • notEqual: Excludes the provided value.
    • in: Keeps items if the collectionFilterBy.value exists in the collectionFilterBy.property (which can be an array).
    • notIn: Opposite of in.
    • contains: Keeps items if any value in the collectionFilterBy.value array exists in the collectionFilterBy.property.

    Chaining vs Merging Filters

    By default, multiple filters are applied in a chain (each pass filters the result of the previous pass). To merge results instead, set filterResultAfterEachPass: 'merge' in collectionOptions.

    Sorting

    Use collectionSortBy to define the order of items in the dropdown. If enableTranslateLabel is true, sorting will respect the translated values.

    filter: {
      collection: [{ value: 1, label: '1' }, { value: 2, label: '2' }],
      collectionFilterBy: [{
         property: 'value',
         operator: OperatorType.notEqual,
         value: 1
      }],
      collectionSortBy: {
         property: 'value',
         sortDesc: true
      },
      model: Filters.multipleSelect
    }
  7. Handle native HTML/DocumentFragment returns from Formatters

    master

    Starting with version 7.x, many built-in formatters have been rewritten to return native HTML elements (HTMLElement) or DocumentFragment instead of HTML strings to ensure CSP (Content Security Policy) compliance and improve performance.

    If you have custom formatters that concatenate strings with the output of built-in formatters, your code may break (e.g., resulting in [object HTMLElement]). You must update your logic to check the type of the returned value using instanceof HTMLElement or instanceof DocumentFragment.

    Key Considerations:

    • DocumentFragment: Allows returning multiple elements without a wrapper. Note that DocumentFragment does not have innerHTML or outerHTML. You can use getHTMLFromFragment(elm) from Slickgrid-Universal to retrieve the HTML.
    • Salesforce Compatibility: If your environment (like Salesforce) does not support DocumentFragment, set the grid option preventDocumentFragmentUsage: true. This will wrap elements in a <span> instead.
    // Example: Updating a custom formatter to handle both strings and native elements
    const customEditableInputFormatter: Formatter = (_row, _cell, value, columnDef, dataContext, grid) => {
      const isEditableLine = checkItemIsEditable(dataContext, columnDef, grid);
      value = (value === null || value === undefined) ? '' : value;
    
      const divElm = document.createElement('div');
      divElm.className = 'editing-field';
    
      if (value instanceof HTMLElement) {
        // If the formatter returned a native element, append it
        divElm.appendChild(value);
      } else {
        // Otherwise, treat it as a string/text
        divElm.textContent = value;
      }
      return divElm;
    };
  8. How grouping and aggregators work together

    master

    Grouping in Angular-Slickgrid provides dynamic, multi-level grouping with filtering and aggregates. To implement grouping, you must provide two distinct pieces of configuration; omitting one will prevent the feature from working:

    1. Aggregators: These are the accumulators (logic) that perform calculations like sums or averages. You define them by passing the column field to be used.
    2. Group Totals Formatter: This is a formatter applied to a column definition that determines how the calculated aggregate result is displayed (e.g., adding a '$' sign or a 'Total: ' prefix).

    An aggregator calculates the value, and the groupTotalsFormatter displays it.

  9. Handle Complex Objects in Select Editors

    master

    When a column field uses dot notation (e.g., user.name), it is treated as a complex object. You can control how the editor interacts with this object using two ColumnEditor properties:

    • complexObjectPath: Overrides the path to the editable object. For example, if the field is user.firstName but you want the editor to target the user object, set this to user.
    • serializeComplexValueFormat: Determines how the selected value is saved back to the data context.
      • 'object' (default): Saves the full object (e.g., { label: 'Bob', value: 'Bob' }).
      • 'flat': Saves only the value (e.g., 'Bob').
    this.columnDefinitions = [{
      id: 'firstName', name: 'First Name', field: 'user.firstName',
      formatter: Formatters.complexObject, 
      editor: {
        model: Editors.SingleSelect,
        complexObjectPath: 'user.middleName',
        serializeComplexValueFormat: 'flat' 
      }
    }];
  10. Use Row Detail to display extra row information

    master

    A Row Detail allows you to open a detail panel containing extra or more detailed information about a specific row. This is useful for displaying data that would otherwise clutter the main grid or impact performance (e.g., full addresses, account info, or related lists).

    Limitations and Constraints

    Due to the complexity of the implementation, you cannot mix Row Detail with the following features:

    • Grouping
    • Pagination
    • Tree Data
    • RowSpan

    Virtual Scrolling Warning

    SlickGrid uses built-in Virtual Scrolling by default. When a Row Detail moves out of the grid viewport, the grid will trigger re-renders.

    Warning: Avoid using dynamic elements (like form inputs) inside a Row Detail if possible. Because of the re-rendering behavior, dynamic elements may reset or re-render unexpectedly when the row scrolls out of and back into view.

  11. How AngularGridInstance provides access to SlickGrid internals

    master

    The AngularGridInstance acts as a bridge between the Angular wrapper and the core SlickGrid engine. When the onAngularGridCreated event fires, it passes an object that exposes two critical properties:

    1. slickGrid: The raw SlickGrid instance. Use this to call native SlickGrid methods like setOptions(), setViewport(), or to subscribe to original SlickGrid events.
    2. dataView: The raw DataView instance. Use this for data-specific operations such as collapseAllGroups(), expandAllGroups(), or managing the underlying data model.

    This pattern allows developers to extend functionality without waiting for official Angular-Slickgrid updates.