diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts index 6a87cf77b..3a61e3691 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts @@ -986,6 +986,7 @@ export default class Example12 { // showResetButtonOnEachEditor: true, onClose: () => Promise.resolve(confirm('You have unsaved changes, are you sure you want to close this window?')), onError: (error) => alert(error.message), + // onRendered: (modalElm) => console.log(modalElm), onSave: (formValues, _selection, dataContextOrUpdatedDatasetPreview) => { const serverResponseDelay = 50; diff --git a/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts b/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts index 0add7300c..a92fece39 100644 --- a/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts +++ b/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts @@ -107,6 +107,9 @@ export interface CompositeEditorOpenDetailOption { /** onError callback allows user to override what the system does when an error (error message & type) is thrown, defaults to console.log */ onError?: (error: OnErrorOption) => void; + /** onRendered callback allows the user to optionally execute something after the modal is created and rendered in the DOM (for example add Bootstrap `bs-data-theme="dark"` attribute to the modal element) */ + onRendered?: (modalElm: HTMLDivElement) => void; + /** * onSave callback will be triggered (when defined) after user clicked the save/apply button, * this callback is used when connecting a backend server with custom code to execute after clicking the save/apply button diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts b/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts index 0d80f3b35..cdc0235b5 100644 --- a/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts +++ b/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts @@ -569,6 +569,22 @@ describe('CompositeEditorService', () => { expect(compositeContainerElm).toBeTruthy(); }); + it('should execute "onRendered" callback after creating & rendering the composite modal window', () => { + const mockProduct = { id: 222, address: { zip: 123456 }, product: { name: 'Product ABC', price: 12.55 } }; + jest.spyOn(gridStub, 'getDataItem').mockReturnValue(mockProduct); + const mockOnRenderedCallback = jest.fn(); + + component = new SlickCompositeEditorComponent(); + component.init(gridStub, container); + component.openDetails({ headerTitle: 'Details', onRendered: mockOnRenderedCallback }); + const compositeContainerElm = document.querySelector('div.slick-editor-modal.slickgrid_123456') as HTMLSelectElement; + + expect(mockOnRenderedCallback).toHaveBeenCalledWith(expect.any(HTMLDivElement)); + expect(component).toBeTruthy(); + expect(component.constructor).toBeDefined(); + expect(compositeContainerElm).toBeTruthy(); + }); + it('should execute "onClose" callback when user confirms the closing of the modal when "onClose" callback is defined', (done) => { const mockProduct = { id: 222, address: { zip: 123456 }, productName: 'Product ABC', price: 12.55, field2: 'Test' }; jest.spyOn(gridStub, 'getDataItem').mockReturnValue(mockProduct); diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.ts b/packages/composite-editor-component/src/slick-composite-editor.component.ts index 02be3b9a8..4a2ff69c3 100644 --- a/packages/composite-editor-component/src/slick-composite-editor.component.ts +++ b/packages/composite-editor-component/src/slick-composite-editor.component.ts @@ -484,6 +484,11 @@ export class SlickCompositeEditorComponent implements ExternalResource { document.body.classList.add('slick-modal-open'); // add backdrop to body this._bindEventService.bind(document.body, 'click', this.handleBodyClicked.bind(this)); + // execute lifecycle callback after the modal window is created and rendered in the DOM + if (typeof this._options.onRendered === 'function') { + this._options.onRendered(this._modalElm); + } + this._editors = {}; this._editorContainers = modalColumns.map(col => modalBodyElm.querySelector(`[data-editorid=${col.id}]`)) || []; this._compositeOptions = { destroy: this.disposeComponent.bind(this), modalType, validationMsgPrefix: '* ', formValues: {}, editors: this._editors };