Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataHelper: try extending the component from mixin instead of using inclide #28811

Draft
wants to merge 2 commits into
base: 25_1
Choose a base branch
from
Draft
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
88 changes: 55 additions & 33 deletions packages/devextreme/js/__internal/data/m_data_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,41 @@ const DATA_SOURCE_FROM_URL_LOAD_MODE_METHOD = '_dataSourceFromUrlLoadMode';
const SPECIFIC_DATA_SOURCE_OPTION = '_getSpecificDataSourceOption';
const NORMALIZE_DATA_SOURCE = '_normalizeDataSource';

export const DataHelperMixin = {
postCtor(): void {
export type Constructor<T> = (new (...args: any[]) => T);
export const DataHelperMixin = <T extends Constructor<object>>(Base: T) => class DataHelperMixin extends Base {
public _dataSource: any;

protected _dataController: any;

protected readyWatcher: any;

private _proxiedDataSourceChangedHandler: any;

private _proxiedDataSourceLoadErrorHandler: any;

private _proxiedDataSourceLoadingChangedHandler: any;

protected _isSharedDataSource: any;

private readonly _dataSourceType: any;

public postCtor() {
// @ts-expect-error ts-error
this.on('disposing', () => {
this._disposeDataSource();
});
},
}

_refreshDataSource(): void {
protected _refreshDataSource() {
this._initDataSource();
this._loadDataSource();
},
}

_initDataSource(): void {
protected _initDataSource(): void {
let dataSourceOptions = SPECIFIC_DATA_SOURCE_OPTION in this
// @ts-expect-error ts-error
? this[SPECIFIC_DATA_SOURCE_OPTION]()
// @ts-expect-error ts-error
: this.option('dataSource');

let widgetDataSourceOptions;
Expand All @@ -39,12 +59,14 @@ export const DataHelperMixin = {
this._dataSource = dataSourceOptions;
} else {
widgetDataSourceOptions = DATA_SOURCE_OPTIONS_METHOD in this
// @ts-expect-error ts-error
? this[DATA_SOURCE_OPTIONS_METHOD]()
: {};

dataSourceType = this._dataSourceType ? this._dataSourceType() : DataSource;

dataSourceOptions = normalizeDataSourceOptions(dataSourceOptions, {
// @ts-expect-error ts-error
fromUrlLoadMode: (DATA_SOURCE_FROM_URL_LOAD_MODE_METHOD in this) && this[DATA_SOURCE_FROM_URL_LOAD_MODE_METHOD](),
});

Expand All @@ -53,15 +75,17 @@ export const DataHelperMixin = {
}

if (NORMALIZE_DATA_SOURCE in this) {
// @ts-expect-error ts-error
this._dataSource = this[NORMALIZE_DATA_SOURCE](this._dataSource);
}

this._addDataSourceHandlers();
this._initDataController();
}
},
}

_initDataController(): void {
protected _initDataController() {
// @ts-expect-error
const dataController = this.option?.('_dataController');
const dataSource = this._dataSource;

Expand All @@ -70,9 +94,9 @@ export const DataHelperMixin = {
} else {
this._dataController = new DataController(dataSource);
}
},
}

_addDataSourceHandlers(): void {
private _addDataSourceHandlers() {
if (DATA_SOURCE_CHANGED_METHOD in this) {
this._addDataSourceChangeHandler();
}
Expand All @@ -86,34 +110,34 @@ export const DataHelperMixin = {
}

this._addReadyWatcher();
},
}

_addReadyWatcher(): void {
private _addReadyWatcher() {
this.readyWatcher = function (isLoading) {
this._ready && this._ready(!isLoading);
}.bind(this);
this._dataSource.on('loadingChanged', this.readyWatcher);
},
}

_addDataSourceChangeHandler(): void {
private _addDataSourceChangeHandler() {
const dataSource = this._dataSource;
this._proxiedDataSourceChangedHandler = function (e) {
this[DATA_SOURCE_CHANGED_METHOD](dataSource.items(), e);
}.bind(this);
dataSource.on('changed', this._proxiedDataSourceChangedHandler);
},
}

_addDataSourceLoadErrorHandler(): void {
private _addDataSourceLoadErrorHandler() {
this._proxiedDataSourceLoadErrorHandler = this[DATA_SOURCE_LOAD_ERROR_METHOD].bind(this);
this._dataSource.on('loadError', this._proxiedDataSourceLoadErrorHandler);
},
}

_addDataSourceLoadingChangedHandler(): void {
private _addDataSourceLoadingChangedHandler() {
this._proxiedDataSourceLoadingChangedHandler = this[DATA_SOURCE_LOADING_CHANGED_METHOD].bind(this);
this._dataSource.on('loadingChanged', this._proxiedDataSourceLoadingChangedHandler);
},
}

_loadDataSource(): void {
protected _loadDataSource() {
const dataSource = this._dataSource;
if (dataSource) {
if (dataSource.isLoaded()) {
Expand All @@ -122,22 +146,22 @@ export const DataHelperMixin = {
dataSource.load();
}
}
},
}

_loadSingle(key, value) {
private _loadSingle(key, value) {
key = key === 'this' ? this._dataSource.key() || 'this' : key;
return this._dataSource.loadSingle(key, value);
},
}

_isLastPage(): boolean {
private _isLastPage() {
return !this._dataSource || this._dataSource.isLastPage() || !this._dataSource._pageSize;
},
}

_isDataSourceLoading() {
private _isDataSourceLoading() {
return this._dataSource && this._dataSource.isLoading();
},
}

_disposeDataSource(): void {
protected _disposeDataSource() {
if (this._dataSource) {
if (this._isSharedDataSource) {
delete this._isSharedDataSource;
Expand All @@ -159,11 +183,9 @@ export const DataHelperMixin = {
delete this._proxiedDataSourceLoadErrorHandler;
delete this._proxiedDataSourceLoadingChangedHandler;
}
},
}

getDataSource() {
protected getDataSource() {
return this._dataSource || null;
},
}
};

export default DataHelperMixin;
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { getOuterHeight, getOuterWidth } from '@js/core/utils/size';
import { findTemplates } from '@js/core/utils/template_manager';
import { isDefined, isFunction, isPlainObject } from '@js/core/utils/type';
import type { DataSourceOptions } from '@js/data/data_source';
import DataHelperMixin from '@js/data_helper';
import type {
Cancelable, DxEvent, EventInfo, ItemInfo,
} from '@js/events';
Expand All @@ -35,6 +34,7 @@ import { focusable } from '@js/ui/widget/selectors';
import { getPublicElement } from '@ts/core/m_element';
import type { OptionChanged } from '@ts/core/widget/types';
import Widget from '@ts/core/widget/widget';
import { DataHelperMixin } from '@ts/data/m_data_helper';
import CollectionWidgetItem from '@ts/ui/collection/m_item';

const COLLECTION_CLASS = 'dx-collection';
Expand Down Expand Up @@ -91,7 +91,11 @@ export interface CollectionWidgetBaseProperties<

focusOnSelectedItem?: boolean;

encodeNoDataText?: boolean;

_itemAttributes?: Record<string, string>;

selectOnFocus?: boolean;
}

class CollectionWidget<
Expand All @@ -101,7 +105,7 @@ class CollectionWidget<
TItem extends ItemLike = any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
TKey = any,
> extends Widget<TProperties> {
> extends DataHelperMixin(Widget)<TProperties> {
private _focusedItemId?: string;

// eslint-disable-next-line no-restricted-globals
Expand All @@ -121,6 +125,8 @@ class CollectionWidget<

_itemFocusHandler?: () => void;

onFocusedItemChanged?: (event?: Partial<EventInfo<unknown> & ItemInfo<TItem>>) => void;

_inkRipple?: {
showWave: (config: {
element: dxElementWrapper;
Expand Down Expand Up @@ -234,14 +240,12 @@ class CollectionWidget<

_init(): void {
this._compileDisplayGetter();
// @ts-expect-error ts-error
this._initDataController();
super._init();

this._activeStateUnit = `.${ITEM_CLASS}`;

this._cleanRenderedItems();
// @ts-expect-error ts-error
this._refreshDataSource();
}

Expand Down Expand Up @@ -575,7 +579,7 @@ class CollectionWidget<
this._updateFocusedItemState($target, true);
// @ts-expect-error ts-error
this.onFocusedItemChanged(this.getFocusedItemId());
// @ts-expect-error ts-error

const { selectOnFocus } = this.option();
const isTargetDisabled = this._isDisabled($target);

Expand Down Expand Up @@ -683,7 +687,6 @@ class CollectionWidget<
this._invalidate();
break;
case 'dataSource':
// @ts-expect-error ts-error
this._refreshDataSource();
// @ts-expect-error ts-error
this._renderEmptyMessage();
Expand All @@ -709,7 +712,6 @@ class CollectionWidget<
this._attachContextMenuEvent();
break;
case 'onFocusedItemChanged':
// @ts-expect-error ts-error
this.onFocusedItemChanged = this._createActionByOption('onFocusedItemChanged');
break;
case 'selectOnFocus':
Expand Down Expand Up @@ -742,7 +744,6 @@ class CollectionWidget<

_loadNextPage(): Promise<unknown> {
this._expectNextPageLoading();
// @ts-expect-error ts-error
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return this._dataController.loadNextPage();
}
Expand Down Expand Up @@ -866,7 +867,6 @@ class CollectionWidget<

_initMarkup(): void {
super._initMarkup();
// @ts-expect-error ts-error
this.onFocusedItemChanged = this._createActionByOption('onFocusedItemChanged');

this.$element().addClass(COLLECTION_CLASS);
Expand Down Expand Up @@ -1355,8 +1355,8 @@ class CollectionWidget<
_renderEmptyMessage(items: TItem[]): void {
// eslint-disable-next-line no-param-reassign
items = items || this.option('items');
const noDataText = this.option('noDataText');
// @ts-expect-error ts-error
const { noDataText } = this.option();

// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const hideNoData = !noDataText || (items && items.length) || this._dataController.isLoading();

Expand All @@ -1371,11 +1371,11 @@ class CollectionWidget<
this._$noData = this._$noData ?? $('<div>').addClass('dx-empty-message');
this._$noData.appendTo(this._emptyMessageContainer());

if (this.option('encodeNoDataText')) {
// @ts-expect-error ts-error
const { encodeNoDataText } = this.option();

if (encodeNoDataText) {
this._$noData.text(noDataText);
} else {
// @ts-expect-error ts-error
this._$noData.html(noDataText);
}
}
Expand Down Expand Up @@ -1484,7 +1484,7 @@ class CollectionWidget<
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(CollectionWidget as any).include(DataHelperMixin);
// (CollectionWidget as any).include(DataHelperMixin);

// @ts-expect-error ts-error
CollectionWidget.ItemClass = CollectionWidgetItem;
Expand Down
1 change: 0 additions & 1 deletion packages/devextreme/js/__internal/ui/menu/m_menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ class Menu extends MenuBase {
});

return extend(menuOptions, {
// @ts-expect-error
dataSource: this.getDataSource(),
animationEnabled: !!this.option('animation'),
onItemClick: this._treeviewItemClickHandler.bind(this),
Expand Down
2 changes: 1 addition & 1 deletion packages/devextreme/js/common/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { errorHandler, setErrorHandler } from './data/errors';
import LocalStore from './data/local_store';
import query from './data/query';
import { base64_encode, compileGetter, compileSetter } from './data/utils';
import DataHelperMixin from '../__internal/data/m_data_helper';
import DataHelperMixin from './data/data_helper';
import ODataContext from './data/odata/context';
import ODataStore from './data/odata/store';
import { EdmLiteral, keyConverters } from './data/odata/utils';
Expand Down
Loading