Skip to content

Commit 4d7b002

Browse files
committed
simplify appointmentRendered callback
1 parent 86c72f0 commit 4d7b002

3 files changed

Lines changed: 81 additions & 42 deletions

File tree

packages/devextreme/js/__internal/scheduler/appointments_new/appointment/base_appointment.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import messageLocalization from '@js/common/core/localization/message';
22
import registerComponent from '@js/core/component_registrator';
3+
import type { DxElement } from '@js/core/element';
34
import type { dxElementWrapper } from '@js/core/renderer';
45
import $ from '@js/core/renderer';
56
import { when } from '@js/core/utils/deferred';
67
import { getPublicElement } from '@ts/core/m_element';
78
import { EmptyTemplate } from '@ts/core/templates/m_empty_template';
89
import { FunctionTemplate } from '@ts/core/templates/m_function_template';
910
import type { TemplateBase } from '@ts/core/templates/m_template_base';
10-
import type { DefaultActionArgs } from '@ts/core/widget/component';
1111
import type { DOMComponentProperties } from '@ts/core/widget/dom_component';
1212
import DOMComponent from '@ts/core/widget/dom_component';
1313
import type { SafeAppointment, TargetedAppointment } from '@ts/scheduler/types';
@@ -16,11 +16,6 @@ import type { AppointmentDataAccessor } from '@ts/scheduler/utils/data_accessor/
1616
import { APPOINTMENT_CLASSES, APPOINTMENT_TYPE_CLASSES } from '../const';
1717
import { DateFormatType, getDateTextFromTargetAppointment } from '../utils/get_date_text';
1818

19-
export interface AppointmentRenderedEvent extends DefaultActionArgs<BaseAppointment> {
20-
appointmentData: SafeAppointment;
21-
targetedAppointmentData: TargetedAppointment;
22-
}
23-
2419
export interface BaseAppointmentProperties
2520
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2621
extends DOMComponentProperties<BaseAppointment<any>>
@@ -29,7 +24,11 @@ export interface BaseAppointmentProperties
2924
targetedAppointmentData: TargetedAppointment;
3025
appointmentTemplate: TemplateBase;
3126

32-
onAppointmentRendered: (e: AppointmentRenderedEvent) => void;
27+
onAppointmentRendered: (e: {
28+
element: DxElement,
29+
appointmentData: SafeAppointment;
30+
targetedAppointmentData: TargetedAppointment;
31+
}) => void;
3332

3433
getDataAccessor: () => AppointmentDataAccessor;
3534
getResourceColor: () => Promise<string | undefined>;
@@ -48,18 +47,12 @@ export class BaseAppointment<
4847

4948
private defaultAppointmentTemplate!: FunctionTemplate;
5049

51-
private appointmentRenderedAction!: BaseAppointmentProperties['onAppointmentRendered'];
52-
5350
override _init(): void {
5451
super._init();
5552

5653
this.defaultAppointmentTemplate = new FunctionTemplate((options) => {
5754
this.defaultAppointmentContent($(options.container));
5855
});
59-
60-
this.appointmentRenderedAction = this._createActionByOption('onAppointmentRendered', {
61-
excludeValidators: ['disabled', 'readOnly'],
62-
});
6356
}
6457

6558
override _initMarkup(): void {
@@ -137,8 +130,8 @@ export class BaseAppointment<
137130
});
138131

139132
when($renderPromise).done(() => {
140-
// @ts-expect-error 'component' property is set by the action
141-
this.appointmentRenderedAction({
133+
this.option().onAppointmentRendered({
134+
element: getPublicElement(this.$element()),
142135
appointmentData: this.appointmentData,
143136
targetedAppointmentData: this.targetedAppointmentData,
144137
});

packages/devextreme/js/__internal/scheduler/appointments_new/appointments.test.ts

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import $ from '@js/core/renderer';
66
import fx from '../../../common/core/animation/fx';
77
import { mockAppointmentDataAccessor } from '../__mock__/appointment_data_accessor.mock';
88
import { getResourceManagerMock } from '../__mock__/resource_manager.mock';
9+
import type { ResourceConfig } from '../utils/loader/types';
910
import type { AppointmentDataSource } from '../view_model/m_appointment_data_source';
1011
import {
1112
mockAgendaViewModel,
@@ -25,13 +26,13 @@ const mockAppointmentDataSource = (): AppointmentDataSource => ({
2526
getUpdatedAppointmentKeys: () => [],
2627
} as unknown as AppointmentDataSource);
2728

28-
const getAppointmentsProperties = (
29-
options: Partial<AppointmentsProperties> = {},
30-
): AppointmentsProperties => ({
29+
const getAppointmentsProperties = (options: {
30+
resources?: ResourceConfig[]
31+
} = {}): AppointmentsProperties => ({
3132
getAppointmentDataSource: mockAppointmentDataSource,
32-
getResourceManager: () => getResourceManagerMock([]),
33+
getResourceManager: () => getResourceManagerMock(options.resources ?? []),
3334
getDataAccessor: () => mockAppointmentDataAccessor,
34-
...options,
35+
currentView: 'week',
3536
} as AppointmentsProperties);
3637

3738
const createAppointments = (
@@ -91,7 +92,10 @@ describe('Appointments', () => {
9192
});
9293

9394
it('should render view model with agenda appointments', () => {
94-
const instance = createAppointments(getAppointmentsProperties());
95+
const instance = createAppointments({
96+
...getAppointmentsProperties(),
97+
currentView: 'agenda',
98+
});
9599
instance.option('viewModel', [
96100
mockAgendaViewModel(defaultAppointmentData, { sortedIndex: 0 }),
97101
]);
@@ -135,17 +139,35 @@ describe('Appointments', () => {
135139
});
136140

137141
it('should render allDay appointment to the allDay container', () => {
138-
const allDayData = { ...defaultAppointmentData, allDay: true };
139142
const $allDayContainer = $('.allday-container');
140143

141-
const instance = createAppointments(getAppointmentsProperties({ $allDayContainer }));
144+
const instance = createAppointments({
145+
...getAppointmentsProperties(),
146+
$allDayContainer,
147+
});
142148
instance.option('viewModel', [
143-
mockGridViewModel(allDayData, { sortedIndex: 0, allDay: true }),
149+
mockGridViewModel({ ...defaultAppointmentData, allDay: true }, { sortedIndex: 0 }),
144150
]);
145151

146152
expect(instance.$element().find(`.${APPOINTMENT_CLASSES.CONTAINER}`).length).toBe(0);
147153
expect($allDayContainer.find(`.${APPOINTMENT_CLASSES.CONTAINER}`).length).toBe(1);
148154
});
155+
156+
it('should not render allDay agenda appointment to the allDay container', () => {
157+
const $allDayContainer = $('.allday-container');
158+
159+
const instance = createAppointments({
160+
...getAppointmentsProperties(),
161+
$allDayContainer,
162+
currentView: 'agenda',
163+
});
164+
instance.option('viewModel', [
165+
mockAgendaViewModel({ ...defaultAppointmentData, allDay: true }, { sortedIndex: 0 }),
166+
]);
167+
168+
expect(instance.$element().find(`.${APPOINTMENT_CLASSES.CONTAINER}`).length).toBe(1);
169+
expect($allDayContainer.find(`.${APPOINTMENT_CLASSES.CONTAINER}`).length).toBe(0);
170+
});
149171
});
150172

151173
describe('Partial rendering', () => {
@@ -263,16 +285,38 @@ describe('Appointments', () => {
263285
});
264286
});
265287

288+
describe('Resources', () => {
289+
it('should apply resource color', async () => {
290+
const instance = createAppointments({
291+
...getAppointmentsProperties({
292+
resources: [{
293+
fieldExpr: 'roomId',
294+
dataSource: [{ text: 'Room 1', id: 1, color: 'red' }],
295+
}],
296+
}),
297+
});
298+
instance.option('viewModel', [
299+
mockGridViewModel({ ...defaultAppointmentData, roomId: 1 }, { sortedIndex: 0 }),
300+
]);
301+
302+
await new Promise(process.nextTick);
303+
304+
const $appointment = instance.$element().find(`.${APPOINTMENT_CLASSES.CONTAINER}`).first();
305+
expect($appointment.css('backgroundColor')).toBe('red');
306+
});
307+
});
308+
266309
describe('onAppointmentRendered', () => {
267-
it('should be called with correct arguments when grid appointment is rendered', async () => {
310+
it('should be called with correct arguments when grid appointment is rendered', () => {
268311
const onAppointmentRendered = jest.fn();
269-
const instance = createAppointments(getAppointmentsProperties({ onAppointmentRendered }));
312+
const instance = createAppointments({
313+
...getAppointmentsProperties(),
314+
onAppointmentRendered,
315+
});
270316
instance.option('viewModel', [
271317
mockGridViewModel(defaultAppointmentData, { sortedIndex: 0 }),
272318
]);
273319

274-
await new Promise(process.nextTick);
275-
276320
expect(onAppointmentRendered).toHaveBeenCalledTimes(1);
277321
expect(onAppointmentRendered).toHaveBeenCalledWith(
278322
expect.objectContaining({
@@ -284,15 +328,16 @@ describe('Appointments', () => {
284328
);
285329
});
286330

287-
it('should be called with correct arguments when agenda appointment is rendered', async () => {
331+
it('should be called with correct arguments when agenda appointment is rendered', () => {
288332
const onAppointmentRendered = jest.fn();
289-
const instance = createAppointments(getAppointmentsProperties({ onAppointmentRendered }));
333+
const instance = createAppointments({
334+
...getAppointmentsProperties(),
335+
onAppointmentRendered,
336+
});
290337
instance.option('viewModel', [
291338
mockAgendaViewModel(defaultAppointmentData, { sortedIndex: 0 }),
292339
]);
293340

294-
await new Promise(process.nextTick);
295-
296341
expect(onAppointmentRendered).toHaveBeenCalledTimes(1);
297342
expect(onAppointmentRendered).toHaveBeenCalledWith(
298343
expect.objectContaining({
@@ -304,28 +349,30 @@ describe('Appointments', () => {
304349
);
305350
});
306351

307-
it('should not be called when appointment collector is rendered', async () => {
352+
it('should not be called when appointment collector is rendered', () => {
308353
const onAppointmentRendered = jest.fn();
309-
const instance = createAppointments(getAppointmentsProperties({ onAppointmentRendered }));
354+
const instance = createAppointments({
355+
...getAppointmentsProperties(),
356+
onAppointmentRendered,
357+
});
310358
instance.option('viewModel', [
311359
mockAppointmentCollectorViewModel(defaultAppointmentData, { sortedIndex: 0 }),
312360
]);
313361

314-
await new Promise(process.nextTick);
315-
316362
expect(onAppointmentRendered).not.toHaveBeenCalled();
317363
});
318364

319-
it('should be called several times when several appointments are rendered', async () => {
365+
it('should be called several times when several appointments are rendered', () => {
320366
const onAppointmentRendered = jest.fn();
321-
const instance = createAppointments(getAppointmentsProperties({ onAppointmentRendered }));
367+
const instance = createAppointments({
368+
...getAppointmentsProperties(),
369+
onAppointmentRendered,
370+
});
322371
instance.option('viewModel', [
323372
mockGridViewModel({ ...defaultAppointmentData, text: 'Appointment 1' }, { sortedIndex: 0 }),
324373
mockGridViewModel({ ...defaultAppointmentData, text: 'Appointment 2' }, { sortedIndex: 1 }),
325374
]);
326375

327-
await new Promise(process.nextTick);
328-
329376
expect(onAppointmentRendered).toHaveBeenCalledTimes(2);
330377
expect(onAppointmentRendered).toHaveBeenNthCalledWith(
331378
1,

packages/devextreme/js/__internal/scheduler/m_scheduler.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import dateLocalization from '@js/common/core/localization/date';
33
import messageLocalization from '@js/common/core/localization/message';
44
import registerComponent from '@js/core/component_registrator';
55
import config from '@js/core/config';
6-
import type { DxElement } from '@js/core/element';
76
import { getPublicElement } from '@js/core/element';
87
import type { dxElementWrapper } from '@js/core/renderer';
98
import $ from '@js/core/renderer';
@@ -1051,7 +1050,7 @@ class Scheduler extends SchedulerOptionsBaseWidget {
10511050
onAppointmentRendered: (e) => {
10521051
// @ts-expect-error 'component' property is set by action
10531052
this.appointmentRenderedAction({
1054-
appointmentElement: e.element as DxElement,
1053+
appointmentElement: e.element,
10551054
appointmentData: e.appointmentData,
10561055
targetedAppointmentData: e.targetedAppointmentData,
10571056
});

0 commit comments

Comments
 (0)