Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
},
"dependencies": {
"@ngx-translate/core": "^15.0.0",
"@slickgrid-universal/common": "~5.13.0",
"@slickgrid-universal/custom-footer-component": "~5.13.0",
"@slickgrid-universal/empty-warning-component": "~5.13.0",
"@slickgrid-universal/common": "~5.13.1",
"@slickgrid-universal/custom-footer-component": "~5.13.1",
"@slickgrid-universal/empty-warning-component": "~5.13.1",
"@slickgrid-universal/event-pub-sub": "~5.13.0",
"@slickgrid-universal/pagination-component": "~5.13.0",
"@slickgrid-universal/row-detail-view-plugin": "~5.13.0",
"@slickgrid-universal/rxjs-observable": "~5.13.0",
"@slickgrid-universal/pagination-component": "~5.13.1",
"@slickgrid-universal/row-detail-view-plugin": "~5.13.1",
"@slickgrid-universal/rxjs-observable": "~5.13.1",
"dequal": "^2.0.3",
"rxjs": "^7.8.2"
},
Expand Down Expand Up @@ -88,7 +88,7 @@
"@angular/platform-browser": "^18.2.13",
"@angular/platform-browser-dynamic": "^18.2.13",
"@angular/router": "^18.2.13",
"@faker-js/faker": "^9.5.1",
"@faker-js/faker": "^9.6.0",
"@fnando/sparkline": "^0.3.10",
"@formkit/tempo": "^0.1.2",
"@ng-select/ng-select": "^13.9.1",
Expand All @@ -98,12 +98,12 @@
"@nx/vite": "^20.6.1",
"@popperjs/core": "^2.11.8",
"@release-it/conventional-changelog": "^10.0.0",
"@slickgrid-universal/composite-editor-component": "~5.13.0",
"@slickgrid-universal/custom-tooltip-plugin": "~5.13.0",
"@slickgrid-universal/excel-export": "~5.13.0",
"@slickgrid-universal/graphql": "~5.13.0",
"@slickgrid-universal/odata": "~5.13.0",
"@slickgrid-universal/text-export": "~5.13.0",
"@slickgrid-universal/composite-editor-component": "~5.13.1",
"@slickgrid-universal/custom-tooltip-plugin": "~5.13.1",
"@slickgrid-universal/excel-export": "~5.13.1",
"@slickgrid-universal/graphql": "~5.13.1",
"@slickgrid-universal/odata": "~5.13.1",
"@slickgrid-universal/text-export": "~5.13.1",
"@types/fnando__sparkline": "^0.3.7",
"@types/node": "^22.13.10",
"@types/sortablejs": "^1.15.8",
Expand Down
1 change: 1 addition & 0 deletions src/app/examples/grid45-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<h4>{{ model.companyName }} - Order Details (id: {{ model.id }})</h4>
<div class="container-fluid">
<angular-slickgrid
class="innergrid"
[gridId]="innerGridId"
[columnDefinitions]="innerColDefs"
[gridOptions]="innerGridOptions"
Expand Down
4 changes: 2 additions & 2 deletions src/app/examples/grid45-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface OrderData {
}

@Component({
styles: ['.detail-label { display: inline-flex; align-items: center; gap: 4px; padding: 4px; }', 'label { font-weight: 600; }'],
styles: ['.innergrid { --slick-header-menu-display: inline-block; }'],
templateUrl: './grid45-detail.component.html',
encapsulation: ViewEncapsulation.None,
})
Expand All @@ -47,7 +47,7 @@ export class Grid45DetailComponent implements OnDestroy, OnInit {
}

ngOnDestroy(): void {
console.log('destroying row detail');
console.log('destroying row detail', this.model.id);
}

angularGridReady(angularGrid: AngularGridInstance) {
Expand Down
11 changes: 11 additions & 0 deletions src/app/examples/grid45.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ <h2>
Use Inner Grid State/Presets
</span>
</label>

<label class="checkbox-inline control-label ms-2" for="useResizeAutoHeight">
<input
type="checkbox"
id="useResizeAutoHeight"
data-test="use-auto-height"
[checked]="isUsingAutoHeight"
(click)="changeUsingResizerAutoHeight()"
/>
Use <code>autoResize.autoHeight</code>
</label>
</span>
</div>
</div>
Expand Down
13 changes: 12 additions & 1 deletion src/app/examples/grid45.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export class Grid45Component implements OnDestroy, OnInit {
gridOptions!: GridOption;
angularGrid!: AngularGridInstance;
dataset: Distributor[] = [];
detailViewRowCount = 8;
detailViewRowCount = 9;
hideSubTitle = false;
isUsingInnerGridStatePresets = false;
isUsingAutoHeight = false;
serverWaitDelay = FAKE_SERVER_DELAY;

get rowDetailInstance(): SlickRowDetailView {
Expand Down Expand Up @@ -100,6 +101,7 @@ export class Grid45Component implements OnDestroy, OnInit {
this.gridOptions = {
autoResize: {
container: '#demo-container',
autoHeight: this.isUsingAutoHeight, // works with/without autoHeight
bottomPadding: 20,
},
autoHeight: false,
Expand Down Expand Up @@ -159,6 +161,15 @@ export class Grid45Component implements OnDestroy, OnInit {
return true;
}

changeUsingResizerAutoHeight() {
this.isUsingAutoHeight = !this.isUsingAutoHeight;
this.angularGrid.slickGrid?.setOptions({
autoResize: { ...this.gridOptions.autoResize, autoHeight: this.isUsingAutoHeight },
});
this.angularGrid.resizerService.resizeGrid();
return true;
}

closeAllRowDetail() {
this.rowDetailInstance?.collapseAll();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,24 +176,24 @@ describe('SlickRowDetailView', () => {
vi.spyOn(gridStub, 'getOptions').mockReturnValue(gridOptionsMock);

plugin.init(gridStub);
const output = await (gridOptionsMock.rowDetailView as RowDetailView).preTemplate!();
const output = (await (gridOptionsMock.rowDetailView as RowDetailView).preTemplate!()) as HTMLElement;

expect(output).toEqual(`<div class="${PRELOAD_CONTAINER_PREFIX}"></div>`);
expect(output.outerHTML).toEqual(`<div class="${PRELOAD_CONTAINER_PREFIX}"></div>`);
});

it('should provide a sanitized "postTemplate" when only a "viewComponent" is provided (meaning no "postTemplate" is originally provided)', async () => {
(gridOptionsMock.rowDetailView as RowDetailView).viewComponent = TestComponent;
vi.spyOn(gridStub, 'getOptions').mockReturnValue(gridOptionsMock);

const output = await gridOptionsMock.rowDetailView!.postTemplate!({ id: 'field1', field: 'field1' });
expect(output).toEqual(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}field1"></div>`);
const output = (await gridOptionsMock.rowDetailView!.postTemplate!({ id: 'field1', field: 'field1' })) as HTMLElement;
expect(output.outerHTML).toEqual(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}field1"></div>`);
});

it('should define "datasetIdPropertyName" with different "id" and provide a sanitized "postTemplate" when only a "viewComponent" is provided (meaning no "postTemplate" is originally provided)', async () => {
(gridOptionsMock.rowDetailView as RowDetailView).viewComponent = TestComponent;
gridOptionsMock.datasetIdPropertyName = 'rowId';
const output = await gridOptionsMock.rowDetailView!.postTemplate!({ rowId: 'field1', field: 'field1' });
expect(output).toEqual(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}field1"></div>`);
const output = (await gridOptionsMock.rowDetailView!.postTemplate!({ rowId: 'field1', field: 'field1' })) as HTMLElement;
expect(output.outerHTML).toEqual(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}field1"></div>`);
});

describe('registered addon', () => {
Expand Down
50 changes: 23 additions & 27 deletions src/app/modules/angular-slickgrid/extensions/slickRowDetailView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
import {
addToArrayWhenNotExists,
castObservableToPromise,
createDomElement,
SlickEventData,
SlickRowSelectionModel,
unsubscribeAll,
Expand Down Expand Up @@ -119,15 +120,12 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
// when those are Angular View/ViewModel, we need to create View Component & provide the html containers to the Plugin (preTemplate/postTemplate methods)
if (!this.gridOptions.rowDetailView.preTemplate) {
this._preloadComponent = this.gridOptions?.rowDetailView?.preloadComponent;
this.addonOptions.preTemplate = () =>
this._grid.sanitizeHtmlString(`<div class="${PRELOAD_CONTAINER_PREFIX}"></div>`) as string;
this.addonOptions.preTemplate = () => createDomElement('div', { className: `${PRELOAD_CONTAINER_PREFIX}` });
}
if (!this.gridOptions.rowDetailView.postTemplate) {
this._viewComponent = this.gridOptions?.rowDetailView?.viewComponent;
this.addonOptions.postTemplate = (itemDetail: any) =>
this._grid.sanitizeHtmlString(
`<div class="${ROW_DETAIL_CONTAINER_PREFIX}${itemDetail[this.datasetIdPropName]}"></div>`
) as string;
createDomElement('div', { className: `${ROW_DETAIL_CONTAINER_PREFIX}${itemDetail[this.datasetIdPropName]}` });
}

// this also requires the Row Selection Model to be registered as well
Expand Down Expand Up @@ -247,21 +245,19 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {

/** Redraw the necessary View Component */
redrawViewComponent(createdView: CreatedView) {
const containerElements = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${createdView.id}`);
if (containerElements?.length >= 0) {
const containerElement = this.gridContainerElement.querySelector(`.${ROW_DETAIL_CONTAINER_PREFIX}${createdView.id}`);
if (containerElement) {
this.renderViewModel(createdView.dataContext);
}
}

/** Render (or re-render) the View Component (Row Detail) */
renderPreloadView() {
const containerElements = this.gridContainerElement.getElementsByClassName(
`${PRELOAD_CONTAINER_PREFIX}`
) as HTMLCollectionOf<HTMLElement>;
if (this._preloadComponent && containerElements?.length >= 0) {
const containerElement = this.gridContainerElement.querySelector(`.${PRELOAD_CONTAINER_PREFIX}`);
if (this._preloadComponent && containerElement) {
const preloadComp = this.angularUtilService.createAngularComponentAppendToDom(
this._preloadComponent,
containerElements[containerElements.length - 1],
containerElement,
{},
{ sanitizer: this._grid.sanitizeHtmlString }
);
Expand All @@ -271,15 +267,14 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {

/** Render (or re-render) the View Component (Row Detail) */
renderViewModel(item: any): CreatedView | undefined {
const containerElements = this.gridContainerElement.getElementsByClassName(
`${ROW_DETAIL_CONTAINER_PREFIX}${item[this.datasetIdPropName]}`
) as HTMLCollectionOf<HTMLElement>;

if (this._viewComponent && containerElements?.length > 0) {
const containerElement = this.gridContainerElement.querySelector(
`.${ROW_DETAIL_CONTAINER_PREFIX}${item[this.datasetIdPropName]}`
);
if (this._viewComponent && containerElement) {
// render row detail
const componentOutput = this.angularUtilService.createAngularComponentAppendToDom(
this._viewComponent,
containerElements[containerElements.length - 1],
containerElement,
{
model: item,
addon: this,
Expand All @@ -291,6 +286,7 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
sanitizer: this._grid.sanitizeHtmlString,
}
);

if (componentOutput?.componentRef) {
const viewObj = this._views.find((obj) => obj.id === item[this.datasetIdPropName]);
if (viewObj) {
Expand All @@ -309,22 +305,21 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {

protected disposeViewByItem(item: any, removeFromArray = false): void {
const foundViewIndex = this._views.findIndex((view: CreatedView) => view.id === item[this.datasetIdPropName]);
if (foundViewIndex >= 0 && foundViewIndex in this._views) {
const expandedView = this._views[foundViewIndex];
this.disposeView(expandedView);
if (foundViewIndex >= 0) {
this.disposeView(this._views[foundViewIndex]);
if (removeFromArray) {
this._views.splice(foundViewIndex, 1);
}
}
}

protected disposeView(expandedView: CreatedView): CreatedView | void {
expandedView.rendered = false;
const compRef = expandedView?.componentRef;
if (compRef) {
this.appRef.detachView(compRef.hostView);
if (typeof compRef?.destroy === 'function') {
compRef.destroy();
expandedView.rendered = false;
}
return expandedView;
}
Expand Down Expand Up @@ -358,8 +353,10 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
}

if (!awaitedItemDetail || !(this.datasetIdPropName in awaitedItemDetail)) {
throw new Error(`[Angular-Slickgrid] could not process the Row Detail, you must make sure that your "process" callback
(a Promise or an HttpClient call returning an Observable) returns an item object that has an "${this.datasetIdPropName}" property`);
throw new Error(
'[Angular-Slickgrid] could not process the Row Detail, you must make sure that your "process" callback ' +
`returns an item object that has an "${this.datasetIdPropName}" property`
);
}

// notify the plugin with the new item details
Expand All @@ -382,8 +379,7 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
dataContext: args.item,
rendered: false,
};
const idPropName = this.gridOptions.datasetIdPropertyName || 'id';
addToArrayWhenNotExists(this._views, viewInfo, idPropName);
addToArrayWhenNotExists(this._views, viewInfo, this.datasetIdPropName);
} else {
// collapsing, so dispose of the View/Component
this.disposeViewByItem(args.item, true);
Expand All @@ -392,7 +388,7 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {

/** When Row comes back to Viewport Range, we need to redraw the View */
protected handleOnRowBackToViewportRange(_e: SlickEventData<OnRowBackToViewportRangeArgs>, args: OnRowBackToViewportRangeArgs) {
const viewModel = Array.from(this._views).find((x) => x.id === args.rowId);
const viewModel = this._views.find((x) => x.id === args.rowId);
if (viewModel && !viewModel.rendered) {
this.redrawViewComponent(viewModel);
}
Expand Down
Loading