Skip to content

@memberjunction/ng-entity-viewer

Angular components for viewing MemberJunction entity data in multiple formats — grid, card, and timeline views — with filtering, selection, toolbar actions, and a comprehensive Before/After cancelable event system.

The @memberjunction/ng-entity-viewer package provides a suite of data presentation components built on AG Grid. The primary component, EntityDataGridComponent, offers infinite scroll, configurable toolbars with custom buttons, server-side sorting, grid state persistence, and a rich event system where “before” events can be canceled. The EntityViewerComponent wraps the grid alongside card and timeline views with a view-mode toggle.

flowchart TD
    subgraph Composite["EntityViewerComponent"]
        TOGGLE[View Mode Toggle] --> GRID[Grid View]
        TOGGLE --> CARDS[Card View]
        TOGGLE --> TIMELINE[Timeline View]
    end

    subgraph Grid["EntityDataGridComponent"]
        TB[Configurable Toolbar] --> AG[AG Grid]
        AG --> INF[Infinite Scroll]
        AG --> SEL[Selection Modes]
        AG --> STATE[State Persistence]
        AG --> EVENTS[Before/After Events]
    end

    subgraph Data["Data Sources"]
        RV[RunView Params] --> Grid
        PRE[Pre-loaded Data] --> Grid
        ENT[Entity Name + Filter] --> Grid
    end

    GRID --> Grid

    style Composite fill:#2d6a9f,stroke:#1a4971,color:#fff
    style Grid fill:#7c5295,stroke:#563a6b,color:#fff
    style Data fill:#2d8659,stroke:#1a5c3a,color:#fff
Terminal window
npm install @memberjunction/ng-entity-viewer ag-grid-angular ag-grid-community
import { EntityViewerModule } from '@memberjunction/ng-entity-viewer';
@NgModule({
imports: [EntityViewerModule]
})
export class MyModule { }
<mj-entity-viewer
[entity]="selectedEntity"
[viewEntity]="myUserView"
[showGridToolbar]="true"
[gridToolbarConfig]="toolbarConfig"
[gridSelectionMode]="'multiple'"
(recordSelected)="onRecordSelected($event)"
(recordOpened)="onRecordOpened($event)"
(addRequested)="onAddNew()"
(exportRequested)="onExport($event)">
</mj-entity-viewer>
<mj-entity-data-grid
[entityName]="'Contacts'"
[extraFilter]="'Status = \'Active\''"
[showToolbar]="true"
[toolbarConfig]="myToolbarConfig"
[selectionMode]="'multiple'"
[PaginationMode]="'infinite'"
[PageSize]="100"
(afterRowClick)="onRowClick($event)"
(afterRowDoubleClick)="onRowDoubleClick($event)"
(newButtonClick)="onAddNew()"
(exportButtonClick)="onExport()">
</mj-entity-data-grid>
onBeforeRowSelect(event: BeforeRowSelectEventArgs) {
// Prevent selecting locked records
if (event.row.Get('Status') === 'Locked') {
event.cancel = true;
event.cancelReason = 'Cannot select locked records';
}
}

EntityDataGridComponent (mj-entity-data-grid)

Section titled “EntityDataGridComponent (mj-entity-data-grid)”

AG Grid-based data grid with rich event system and configurable toolbar.

InputTypeDefaultDescription
ParamsRunViewParams-Primary data source (stored views + dynamic views)
entityNamestring-Entity name for dynamic views
extraFilterstring-Additional WHERE clause filter
searchStringstring-User search string
orderBystring-ORDER BY clause
maxRowsnumber0Max rows to fetch (0 = no limit)
dataBaseEntity[]-Pre-loaded data (bypasses RunView)
AllowLoadbooleantrueEnable/disable data loading
AutoRefreshOnParamsChangebooleantrueAuto-refresh when Params changes
InputTypeDefaultDescription
PaginationMode'client' | 'infinite''client'Pagination strategy
PageSizenumber100Rows per page (infinite mode)
CacheBlockSizenumber100Cache block size (infinite mode)
MaxBlocksInCachenumber10Max cached blocks
InputTypeDefaultDescription
showToolbarbooleantrueShow the toolbar
toolbarConfigGridToolbarConfig-Toolbar configuration
selectionMode'none' | 'single' | 'multiple' | 'checkbox''single'Row selection mode
heightnumber | 'auto' | 'fit-content''auto'Grid height
gridStateViewGridStateConfig-Column/sort state from User View
allowSortingbooleantrueEnable column sorting
allowColumnReorderbooleantrueEnable column reordering
allowColumnResizebooleantrueEnable column resizing
serverSideSortingbooleantrueSort triggers server reload

The grid uses a cancelable event pattern. Before events can be canceled by setting event.cancel = true.

Row Selection Events:

EventArgs TypeDescription
beforeRowSelectBeforeRowSelectEventArgsBefore row is selected
afterRowSelectAfterRowSelectEventArgsAfter row is selected
beforeRowDeselectBeforeRowDeselectEventArgsBefore row is deselected
afterRowDeselectAfterRowDeselectEventArgsAfter row is deselected

Row Click Events:

EventArgs TypeDescription
beforeRowClickBeforeRowClickEventArgsBefore row click processes
afterRowClickAfterRowClickEventArgsAfter row click
beforeRowDoubleClickBeforeRowDoubleClickEventArgsBefore double-click
afterRowDoubleClickAfterRowDoubleClickEventArgsAfter double-click

Data Events:

EventArgs TypeDescription
beforeDataLoadBeforeDataLoadEventArgsBefore data loads
afterDataLoadAfterDataLoadEventArgsAfter data loads
beforeDataRefreshBeforeDataRefreshEventArgsBefore refresh
afterDataRefreshAfterDataRefreshEventArgsAfter refresh

Sorting/Column Events:

EventArgs TypeDescription
beforeSortBeforeSortEventArgsBefore sort changes
afterSortAfterSortEventArgsAfter sort changes
beforeColumnReorderBeforeColumnReorderEventArgsBefore column move
afterColumnReorderAfterColumnReorderEventArgsAfter column move
gridStateChangedGridStateChangedEventColumn state changed

Toolbar Button Events:

EventArgs TypeDescription
newButtonClickvoidAdd/New button clicked
refreshButtonClickvoidRefresh button clicked
deleteButtonClickBaseEntity[]Delete button clicked
exportButtonClickvoidExport button clicked
compareButtonClickBaseEntity[]Compare button clicked
mergeButtonClickBaseEntity[]Merge button clicked
addToListButtonClickBaseEntity[]Add to List clicked

Configure toolbar buttons and behavior:

const toolbarConfig: GridToolbarConfig = {
showSearch: true,
searchPlaceholder: 'Search records...',
searchDebounce: 300,
showRefresh: true,
showAdd: true,
showDelete: true,
showExport: true,
showColumnChooser: true,
showFilterToggle: false,
exportFormats: ['excel', 'csv', 'json'],
showRowCount: true,
showSelectionCount: true,
position: 'top',
customButtons: [
{
id: 'myButton',
text: 'My Action',
icon: 'fa-solid fa-star',
tooltip: 'Do something custom',
position: 'right',
onClick: () => console.log('Clicked!')
}
]
};

Composite component combining grid, cards, and timeline views.

InputTypeDefaultDescription
entityEntityInfo-Entity metadata
recordsBaseEntity[]-Pre-loaded records
viewEntityUserViewEntityExtended-User View for filtering/sorting
viewMode'grid' | 'cards' | 'timeline''grid'Current view mode
filterTextstring-Filter text
sortStateSortState-Sort state
gridStateViewGridStateConfig-Grid column state
showGridToolbarbooleantrueShow grid toolbar
gridToolbarConfigGridToolbarConfig-Toolbar configuration
gridSelectionModeGridSelectionMode'single'Selection mode
OutputEvent TypeDescription
recordSelectedRecordSelectedEventRecord clicked
recordOpenedRecordOpenedEventRecord double-clicked
dataLoadedDataLoadedEventData finished loading
viewModeChangeEntityViewModeView mode changed
filterTextChangestringFilter text changed
sortChangedSortChangedEventSort changed
gridStateChangedGridStateChangedEventGrid state changed
addRequestedvoidAdd button clicked
deleteRequested{ records }Delete button clicked
refreshRequestedvoidRefresh button clicked
exportRequested{ format }Export button clicked

RecycleBinComponent (mj-recycle-bin) and RecycleBinChipComponent (mj-recycle-bin-chip)

Section titled “RecycleBinComponent (mj-recycle-bin) and RecycleBinChipComponent (mj-recycle-bin-chip)”

Slide-in panel that lists hard-deleted records for a single entity and lets a user with Delete permission re-create any of them from its historical RecordChange snapshot. The accompanying chip component is a tiny composite that renders a count-badge button and hosts the panel — drop it into any toolbar in three lines.

The chip is already embedded in EntityViewerComponent and EntityDataGridComponent — both expose a [ShowRecycleBin] input (default true) that you can flip off if you don’t want the chip. Use the standalone components only when building a custom entity viewer.

The chip and panel are gated on entity.UserPermissions.CanDelete. Rationale: there is no native “undelete” permission in MemberJunction, but if a user has the higher-trust permission to delete records of an entity, restoring deleted ones is well within scope. The actual re-create action additionally requires CanCreate; without it the Restore button on each card disables with a tooltip.

The chip auto-hides when:

  • EntityName is null/empty
  • The entity has TrackRecordChanges = false
  • The user lacks CanDelete permission
  • The deleted-record count is zero

This component only surfaces hard-deleted records. Soft-deletes (IsDeleted flags, Status='Inactive', etc.) leave the record visible in normal entity views, so the standard Record Changes panel + restore preview already handles them — no Recycle Bin needed.

Every meaningful action emits a paired before* / after* event. The before* event carries cancel: boolean so consumers can intercept — useful for custom approval workflows, audit logging, or to take over the actual restore execution.

onBeforeRecordRestore(e: BeforeRecordRestoreEventArgs) {
if (!hasComplianceApproval(e.entry)) {
e.cancel = true;
e.cancelReason = 'Awaiting compliance approval';
}
}
InputTypeDefaultDescription
EntityNamestring | nullnullEntity whose deleted records will be listed. Chip hides when null.
ContextUserUserInfo | nullnullOptional context user. Falls back to Metadata.Provider.CurrentUser.

RecycleBinChipComponent / RecycleBinComponent Outputs

Section titled “RecycleBinChipComponent / RecycleBinComponent Outputs”
OutputArgs TypeCancelableDescription
BeforeRecycleBinOpenBeforeRecycleBinOpenEventArgsFires before the deleted-record query runs.
AfterRecycleBinOpenAfterRecycleBinOpenEventArgsFires after the query completes; carries deletedRecordCount.
BeforeRecordRestoreBeforeRecordRestoreEventArgsFires when the user clicks Restore on a card, before the preview opens.
AfterRecordRestoreAfterRecordRestoreEventArgsFires after the user closes the preview; carries success.
BeforeRestoreCommitBeforeRestoreCommitEventArgsFires after the user confirms in the preview but before the insert runs.
AfterRestoreCommitAfterRestoreCommitEventArgsFires after the insert; carries success, newRecordID, errorMessage.

RecycleBinComponent Inputs (when used directly)

Section titled “RecycleBinComponent Inputs (when used directly)”
InputTypeDefaultDescription
VisiblebooleanfalseControls panel visibility. Setting true triggers a load.
EntityNamestring | nullnullRequired. The entity whose deleted records to list.
ContextUserUserInfo | nullnullOptional context user.
MaxRecordsnumber200Max number of cards to load.

EntityViewerComponent and EntityDataGridComponent both expose:

InputTypeDefaultDescription
ShowRecycleBinbooleantrueRenders the Recycle Bin chip in the toolbar/header. Auto-hides when entity isn’t a candidate (no tracking / no permission / no deleted records).
<!-- Composite viewer with the chip turned off -->
<mj-entity-viewer
[entity]="selectedEntity"
[ShowRecycleBin]="false">
</mj-entity-viewer>
<!-- Standalone data grid with explicit chip event handling -->
<mj-entity-data-grid
[entityName]="'Customers'"
[ShowRecycleBin]="true">
</mj-entity-data-grid>

Card-based view with auto-generated layout.

<mj-entity-cards
[entity]="selectedEntity"
[records]="records"
[filterText]="searchFilter"
(recordSelected)="onSelected($event)"
(recordOpened)="onOpened($event)">
</mj-entity-cards>

Semantic color pill for categorical values. Colors are auto-detected based on value:

ColorValues
success (green)active, approved, complete, success
warning (yellow)pending, in progress, draft, waiting
danger (red)failed, error, rejected, cancelled
info (blue)new, info, created, open
neutral (gray)default
<mj-pill [value]="record.Status"></mj-pill>
<mj-entity-data-grid
[entityName]="'Contacts'"
[PaginationMode]="'infinite'"
[PageSize]="100"
[CacheBlockSize]="100"
[MaxBlocksInCache]="10">
</mj-entity-data-grid>
<mj-entity-data-grid
[Params]="{ ViewID: myUserView.ID }"
[AutoPersistState]="true"
[StatePersistDebounce]="5000">
</mj-entity-data-grid>
// Types
import {
GridToolbarConfig,
GridToolbarButton,
GridSelectionMode,
GridColumnConfig,
ViewGridStateConfig,
DataGridSortState,
RecordSelectedEvent,
RecordOpenedEvent
} from '@memberjunction/ng-entity-viewer';
// Event Args
import {
BeforeRowSelectEventArgs,
AfterRowSelectEventArgs,
BeforeRowClickEventArgs,
AfterRowClickEventArgs,
BeforeDataLoadEventArgs,
AfterDataLoadEventArgs,
AfterSortEventArgs
} from '@memberjunction/ng-entity-viewer';
// Recycle Bin
import {
RecycleBinComponent,
RecycleBinChipComponent,
RecycleBinEntry,
BeforeRecycleBinOpenEventArgs,
AfterRecycleBinOpenEventArgs,
BeforeRecordRestoreEventArgs,
AfterRecordRestoreEventArgs,
BeforeRestoreCommitEventArgs,
AfterRestoreCommitEventArgs
} from '@memberjunction/ng-entity-viewer';
PackageDescription
@memberjunction/coreCore framework
@memberjunction/core-entitiesEntity type definitions
@memberjunction/globalGlobal utilities
@memberjunction/export-engineData export engine
@memberjunction/ng-shared-genericShared generic components
@memberjunction/ng-timelineTimeline view component
@memberjunction/ng-filter-builderFilter builder component
@memberjunction/ng-export-serviceExport service and dialog
@memberjunction/ng-record-changesReusable restore preview panel for the Recycle Bin
@memberjunction/ng-ui-componentsProvides mj-slide-panel for the Recycle Bin slide-in
  • @angular/common ^21.x
  • @angular/core ^21.x
  • @angular/forms ^21.x
  • @angular/animations ^21.x
  • ag-grid-angular ^35.x
  • ag-grid-community ^35.x
Terminal window
cd packages/Angular/Generic/entity-viewer
npm run build

ISC