fixed: column drag issue.

optimized: documentation.
This commit is contained in:
Chen Lily 2024-01-26 14:09:52 +08:00
parent 0b9b322b80
commit 984496e08e
5 changed files with 313 additions and 78 deletions

16
lib/ui/dropdown.d.ts vendored
View File

@ -32,7 +32,7 @@ export interface DropdownOptions {
search?: boolean;
/** 搜索的关键字数组 */
searchKeys?: Array<string>;
/** 搜索提示文本,默认值取语言资源 <code>searchHolder</code> "Search..." */
/** 搜索提示文本,默认值取语言资源 `searchHolder` "Search..." */
searchPlaceholder?: string;
/** 焦点索引 */
tabIndex?: Number;
@ -47,7 +47,7 @@ export interface DropdownOptions {
/** 下拉框类 */
export class Dropdown {
/**
* <code>select</code>
* `select`
* @param dom
* @returns
*/
@ -64,16 +64,24 @@ export class Dropdown {
/**
*
* @param item
* @eventProperty
*/
onSelected: (item: DropdownItem) => void;
/**
*
* @param list
* @eventProperty
*/
onSelectedList: (list: Array<DropdownItem>) => void;
/** 下拉框展开时触发 */
/**
*
* @eventProperty
*/
onExpanded: () => void;
/** 下拉框收缩时触发 */
/**
*
* @eventProperty
*/
onCollapsed: () => void;
/** 获取下拉框是否禁用 */

View File

@ -35,13 +35,18 @@ export interface GridColumnDefinition {
align?: "left" | "center" | "right";
/**
* <br/><br/>
* <code>boolean</code> 使<br/><br/>
* <code>string</code> <br/><br/>
* <code>(item: GridItem) => boolean</code> <br/><br/>
* `boolean` 使<br/><br/>
* `string` <br/><br/>
* `(item: GridItem) => boolean` <br/><br/>
*/
enabled?: boolean | string | ((item: GridItem) => boolean);
/** 单元格取值采用该方法返回的值 */
filter?: (item: GridItem) => any;
/**
*
* @param item
* @param editing
* @param body Grid `&lt;tbody&gt;`
*/
filter?: (item: GridItem, editing: boolean, body?: HTMLElement) => any;
/** 单元格以该值填充内容忽略filter与关键字属性 */
text?: string;
/** 列是否可见 */
@ -76,8 +81,8 @@ export interface GridColumnDefinition {
source?: Array<GridSourceItem> | ((item: GridItem) => Array<GridSourceItem> | Promise<Array<GridSourceItem>>);
/** 下拉列表数据源是否缓存结果即行数据未发生变化时仅从source属性获取一次值 */
sourceCache?: boolean;
/** 列为图标类型时以该值设置图标样式(函数上下文为列定义对象),允许值为 <code>fa-light</code>、<code>fa-regular</code>、<code>fa-solid</code> */
iconType?: string;
/** 列为图标类型时以该值设置图标样式(函数上下文为列定义对象),默认值 `fa-light` */
iconType?: "fa-light" | "fa-regular" | "fa-solid";
/** 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象) */
iconClassName?: string | ((item: GridItem) => string);
/** 列为日期类型时以该值作为最小可选日期值 */
@ -92,6 +97,7 @@ export interface GridColumnDefinition {
* @param this Grid
* @param col
* @param flag
* @eventProperty
*/
onAllChecked?: (this: Grid, col: GridColumnDefinition, flag: boolean) => void;
/**
@ -101,6 +107,7 @@ export interface GridColumnDefinition {
* @param value
* @param oldValue
* @param e
* @eventProperty
*/
onChanged?: (this: Grid, item: GridItem, value: boolean | string | Number, oldValue: boolean | string | Number, e?: any) => void;
/**
@ -108,6 +115,7 @@ export interface GridColumnDefinition {
* @param this Grid
* @param item
* @param value
* @eventProperty
*/
onInputEnded?: (this: Grid, item: GridItem, value: string) => void;
/**
@ -115,12 +123,14 @@ export interface GridColumnDefinition {
* @param this Grid
* @param col
* @param selected
* @eventProperty
*/
onFilterOk?: (this: Grid, col: GridColumnDefinition, selected: Array<GridItem>) => void;
/**
*
* @param this Grid
* @param col
* @eventProperty
*/
onFiltered?: (this: Grid, col: GridColumnDefinition) => void;
/**
@ -128,6 +138,7 @@ export interface GridColumnDefinition {
* @param this
* @param item
* @param drop
* @eventProperty
*/
onDropExpanded?: (this: GridColumnDefinition, item: GridItem, drop: Dropdown) => void;
}
@ -138,19 +149,28 @@ export class GridColumn {
*
* @param col
* @returns
* @virtual
*/
static create(col: GridColumnDefinition): HTMLElement;
/**
* <br/><br/>
* <code>__editing</code> {@linkcode leaveEdit} <br/>
* `__editing` {@linkcode leaveEdit} <br/>
* {@linkcode GridDropdownColumn}
* @param trigger e {@linkcode getValue}
* @param col
* @param container
* @param vals <code>values</code>
* @param vals `values`
* @returns
* @virtual
*/
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
/**
*
* @param col
* @returns
* @virtual
*/
static createCaption?(col: GridColumnDefinition): HTMLElement;
/**
*
* @param element
@ -158,59 +178,178 @@ export class GridColumn {
* @param vals
* @param col
* @param grid {@linkcode Grid}
* @virtual
*/
static setValue(element: HTMLElement, val: string | boolean | Number, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
/**
*
* @param e {@linkcode createEdit} <code>trigger</code>
* @param e {@linkcode createEdit} `trigger`
* @param col
* @returns
* @virtual
*/
static getValue(e: any, col: GridColumnDefinition): string | boolean | Number;
/**
*
* @param element
* @param style
* @virtual
*/
static setStyle(element: HTMLElement, style: { [key: string]: string }): void;
/**
*
* @param element
* @param enabled false时代表禁用
* @virtual
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
/**
* <code>__editing</code>
* `__editing`
* @param element
* @param container
* @virtual
*/
static leaveEdit(element: HTMLElement, container: HTMLElement): void;
static leaveEdit?(element: HTMLElement, container: HTMLElement): void;
}
/** 单行文本列 */
export class GridInputColumn extends GridColumn {
/**
* {@linkcode GridColumnDefinition.onInputEnded} <br/>
* <code>true</code> <code>__editing</code> {@linkcode GridColumnDefinition.onInputEnded} <code>onchange</code> <br/>
* `true` `__editing` {@linkcode GridColumnDefinition.onInputEnded} `onchange` <br/>
* {@linkcode GridInputColumn}
*/
static get editing(): boolean;
/**
* @inheritdoc GridColumn.createEdit
* @override
*/
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
/**
* @inheritdoc GridColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
/**
* @inheritdoc GridColumn.getValue
* @override
*/
static getValue(e: any): string;
/**
* @inheritdoc GridColumn.setEnabled
* @override
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
}
/** 多行文本列 */
export class GridTextColumn extends GridInputColumn { }
export class GridTextColumn extends GridInputColumn {
/**
* @inheritdoc GridInputColumn.createEdit
* @override
*/
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
/**
* @inheritdoc GridInputColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
}
/** 下拉选择列 */
export class GridDropdownColumn extends GridColumn { }
export class GridDropdownColumn extends GridColumn {
/**
* @inheritdoc GridColumn.createEdit
* @override
*/
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
/**
* @inheritdoc GridColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition): void;
/**
* @inheritdoc GridColumn.getValue
* @override
*/
static getValue(e: any, col: GridColumnDefinition): string;
/**
* @inheritdoc GridColumn.setEnabled
* @override
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
/**
* @inheritdoc GridColumn.leaveEdit
* @override
*/
static leaveEdit?(element: HTMLElement, container: HTMLElement): void;
}
/** 复选框列 */
export class GridCheckboxColumn extends GridColumn { }
export class GridCheckboxColumn extends GridColumn {
/**
* @inheritdoc GridColumn.createEdit
* @override
*/
static createEdit(trigger: (e: any) => void): HTMLElement;
/**
* @inheritdoc GridColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: boolean): void;
/**
* @inheritdoc GridColumn.getValue
* @override
*/
static getValue(e: any): boolean;
/**
* @inheritdoc GridColumn.setEnabled
* @override
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
}
/** 图标列 */
export class GridIconColumn extends GridColumn { }
export class GridIconColumn extends GridColumn {
/**
* @inheritdoc GridColumn.create
* @override
*/
static create(): HTMLElement;
/**
* @inheritdoc GridColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition): void;
/**
* @inheritdoc GridColumn.setEnabled
* @override
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
}
/** 日期选择列 */
export class GridDateColumn extends GridColumn {
/**
* @inheritdoc GridColumn.createEdit
* @override
*/
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
/**
* @inheritdoc GridColumn.setValue
* @override
*/
static setValue(element: HTMLElement, val: string | Number): void;
/**
* @inheritdoc GridColumn.getValue
* @override
*/
static getValue(e: any): string | Number;
/**
* @inheritdoc GridColumn.setEnabled
* @override
*/
static setEnabled(element: HTMLElement, enabled?: boolean): void;
/**
* M/d/yyyy
* @param date

View File

@ -250,7 +250,7 @@ export class GridCheckboxColumn extends GridColumn {
export class GridIconColumn extends GridColumn {
static create() { return createElement('span', 'col-icon') }
static setValue(element, val, item, col, _grid) {
static setValue(element, val, item, col) {
let className = col.iconClassName;
if (typeof className === 'function') {
className = className.call(col, item.values);
@ -264,7 +264,7 @@ export class GridIconColumn extends GridColumn {
if (typeof type === 'function') {
type = type.call(col, item.values);
}
type ??= 'fa-regular';
type ??= 'fa-light';
if (element.dataset.type !== type || element.dataset.icon !== val) {
const icon = createIcon(type, val);
// const layer = element.children[0];

25
lib/ui/grid/grid.d.ts vendored
View File

@ -24,6 +24,22 @@ interface GridSourceItem {
text: string;
}
/** Grid 语言资源接口 */
interface GridLanguages {
/**
*
*
* @default `( All )`
*/
all: string;
/** “确定”文本,默认值 OK */
ok: string;
/** “重置”文本,默认值 Reset */
reset: string;
/** “空”文本,默认值 ( Null ) */
null: string
}
/** 列排序枚举 */
declare enum GridColumnDirection {
/** 倒序 */
@ -70,7 +86,7 @@ export class Grid {
/** 列定义的数组 */
columns: Array<GridColumnDefinition>;
/** 多语言资源对象 */
langs?: { all: string, ok: string, reset: string };
langs?: GridLanguages;
/** 行数大于等于该值则启用虚模式,默认值 100 */
virtualCount?: Number;
/** 表格行高,默认值 36 */
@ -112,29 +128,34 @@ export class Grid {
* falsenullundefined0
* @param index
* @param colIndex
* @eventProperty
*/
willSelect?: (index: Number, colIndex: Number) => boolean;
/**
* colIndex -1 false
* @param index
* @param colIndex
* @eventProperty
*/
cellClicked?: (index: Number, colIndex: Number) => boolean;
/**
*
* @param index
* @eventProperty
*/
onSelectedRowChanged?: (index?: Number) => void;
/**
* colIndex -1
* @param index
* @param colIndex
* @eventProperty
*/
onCellDblClicked?: (index: Number, colIndex: Number) => void;
/**
*
* @param index
* @eventProperty
*/
onRowDblClicked?: (index: Number) => void;
/**
@ -145,11 +166,13 @@ export class Grid {
* "sort" value 1 -1
* @param colIndex
* @param value
* @eventProperty
*/
onColumnChanged?: (type: GridColumnColumnEvent, colIndex: Number, value: Number | GridColumnDirection) => void;
/**
*
* @param e
* @eventProperty
*/
onBodyScrolled?: (e: Event) => void;

View File

@ -17,7 +17,7 @@ const ColumnChangedType = {
const RefreshInterval = isMobile() ? 32 : 0;
const HoverInternal = 200;
const RedumCount = 4;
const MiniDragOffset = 4;
const MiniDragOffset = 10;
const MiniColumnWidth = 50;
const FilterPanelWidth = 200;
@ -29,15 +29,6 @@ function getClientX(e) {
return cx ?? e.clientX;
}
function getOffsetLeftFromWindow(element) {
let left = 0;
while (element != null) {
left += element.offsetLeft;
element = element.offsetParent;
}
return left;
}
function indexOfParent(target) {
// return [...target.parentElement.children].indexOf(target);
return Array.prototype.indexOf.call(target.parentElement.children, target);
@ -127,7 +118,8 @@ export class Grid {
this.langs = {
all: r('allItem', '( All )'),
ok: r('ok', 'OK'),
reset: r('reset', 'Reset')
reset: r('reset', 'Reset'),
null: r('null', '( Null )')
};
}
@ -190,7 +182,7 @@ export class Grid {
this._var.currentSource = list.filter(it => {
for (let col of this.columns) {
if (Array.isArray(col.filterValues)) {
const v = this._getItemValue(it.values, col.key, col.filter);
const v = this._getItemProp(it.values, false, col);
if (col.filterValues.indexOf(v) < 0) {
return false;
}
@ -485,8 +477,8 @@ export class Grid {
direction = 1;
}
comparer = (a, b) => {
a = this._getItemValue(a.values, col.key, col.filter);
b = this._getItemValue(b.values, col.key, col.filter);
a = this._getItemProp(a.values, true, col);
b = this._getItemProp(b.values, true, col);
if (a == null && typeof b === 'number') {
a = 0;
} else if (typeof a === 'number' && b == null) {
@ -533,7 +525,7 @@ export class Grid {
let left = 0;
for (let col of this.columns) {
if (col.visible === false) {
const hidden = createElement('th');
const hidden = createElement('th', 'column');
hidden.style.display = 'none';
if (col.sortable !== false) {
hidden.dataset.key = col.key;
@ -544,7 +536,17 @@ export class Grid {
}
// style
const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type);
if (col.width > 0) {
let type = this._var.colTypes[col.key];
if (type == null) {
if (isNaN(col.type)) {
type = col.type;
} else {
type = ColumnTypes[col.type];
}
type ??= GridColumn;
this._var.colTypes[col.key] = type;
}
if (col.width > 0 || typeof type.createCaption === 'function') {
// col.autoResize = false;
} else {
this._set(col.key, 'autoResize', true);
@ -600,12 +602,19 @@ export class Grid {
});
wrapper.appendChild(check);
}
const caption = createElement('span');
if (col.captionStyle != null) {
caption.style.cssText = convertCssStyle(col.captionStyle);
let caption;
if (typeof type.createCaption === 'function') {
caption = type.createCaption(col);
} else {
caption = createElement('span');
caption.innerText = col.caption ?? '';
}
if (caption instanceof HTMLElement) {
if (col.captionStyle != null) {
caption.style.cssText = convertCssStyle(col.captionStyle);
}
wrapper.appendChild(caption);
}
caption.innerText = col.caption ?? '';
wrapper.appendChild(caption);
// order arrow
if (col.sortable) {
th.appendChild(createElement('layer', 'arrow'));
@ -906,13 +915,15 @@ export class Grid {
}
}
_changingColumnOrder(index, offset, x, offsetLeft, scrollLeft) {
_changingColumnOrder(index, offset, mouse, draggerCellLeft) {
const children = this._var.refs.header.children;
let element = children[index];
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - offsetLeft + offset}px; width: ${element.style.width}; display: block`;
offset = x + scrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - draggerCellLeft + offset}px; width: ${element.style.width}; display: block`;
// offset = x + gridScrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
offset += mouse;
let idx;
if (offset < 0) {
const toLeft = offset < 0;
if (toLeft) {
offset = -offset;
for (let i = index - 1; i >= 0 && offset >= 0; i -= 1) {
element = children[i];
@ -943,13 +954,27 @@ export class Grid {
}
idx ??= count - 1;
}
if (idx !== this._var.colAttrs.__orderIndex) {
this._var.colAttrs.__orderIndex = idx;
if (idx !== this._var.colAttrs.__orderIndex || this._var.refs.draggerCursor.style.display !== 'block') {
element = children[idx];
if (element == null) {
return;
}
this._var.refs.draggerCursor.style.cssText = `left: ${element.offsetLeft - offsetLeft}px; display: block`;
this._var.colAttrs.__orderIndex = idx;
// avoid `offsetLeft` of hidden header to be 0
let left;
if (element.style.display === 'none') {
left = 0;
while (left === 0 && (element = children[++idx]) != null) {
left = element.offsetLeft;
}
if (!toLeft && left === 0) {
left = draggerCellLeft;
}
} else {
left = element.offsetLeft;
}
// set position of dragger cursor
this._var.refs.draggerCursor.style.cssText = `left: ${left - draggerCellLeft}px; display: block`;
}
}
@ -1057,14 +1082,21 @@ export class Grid {
}
}
_getItemValue(item, key, filter) {
_getItemProp(item, editing, col) {
let value;
if (typeof filter === 'function') {
value = filter(item, false, this._var.refs.body);
if (typeof col?.filter === 'function') {
value = col.filter(item, editing, this._var.refs.body);
} else {
value = item[key];
value = item[col.key];
}
return value?.Value ?? value;
if (value == null) {
return value;
}
const prop = editing ? 'Value' : 'DisplayValue';
if (Object.prototype.hasOwnProperty.call(value, prop)) {
return value[prop];
}
return value;
}
_getRowTarget(target) {
@ -1174,19 +1206,35 @@ export class Grid {
} else {
const dict = Object.create(null);
for (let item of this._var.source) {
const val = this._getItemValue(item.values, col.key, col.filter);
if (!Object.hasOwnProperty.call(dict, val)) {
const v = item.values[col.key];
dict[val] = {
let displayValue = this._getItemProp(item.values, false, col);
if (displayValue == null) {
displayValue = this.langs.null;
}
if (!Object.hasOwnProperty.call(dict, displayValue)) {
const val = this._getItemProp(item.values, true, col);
dict[displayValue] = {
Value: val,
DisplayValue: typeof col.filter === 'function' ? col.filter(item.values) : v?.DisplayValue ?? v
DisplayValue: displayValue
};
}
}
array = Object.values(dict)
.sort((a, b) => {
a = a?.Value ?? a;
b = b?.Value ?? b;
if (a == null && b == null) {
return 0;
}
if (a == null && b != null) {
return -1;
}
if (a != null && b == null) {
return 1;
}
if (Object.prototype.hasOwnProperty.call(a, 'Value')) {
a = a.Value;
}
if (Object.prototype.hasOwnProperty.call(b, 'Value')) {
b = b.Value;
}
return a > b ? 1 : a < b ? -1 : 0;
});
}
@ -1197,7 +1245,7 @@ export class Grid {
}
return {
Value: i,
DisplayValue: i == null ? '' : i
DisplayValue: i == null ? this.langs.null : i
};
});
this._fillFilterList(col, itemlist, array, itemall);
@ -1207,8 +1255,16 @@ export class Grid {
searchbox.addEventListener('input', e => {
const key = e.currentTarget.value.toLowerCase();
const items = key.length === 0 ? array : array.filter(i => {
const displayValue = i?.DisplayValue ?? i;
return String(displayValue ?? '').toLowerCase().includes(key);
let displayValue;
if (i != null && Object.prototype.hasOwnProperty.call(i, 'DisplayValue')) {
displayValue = i.DisplayValue;
} else {
displayValue = i;
}
if (displayValue == null) {
displayValue = this.langs.null;
}
return String(displayValue).toLowerCase().includes(key);
});
this._fillFilterList(col, itemlist, items, itemall);
});
@ -1223,7 +1279,7 @@ export class Grid {
if (typeof col.onFilterOk === 'function') {
col.onFilterOk.call(this, col, array);
} else {
col.filterValues = array.map(a => a.Value);
col.filterValues = array.map(a => a.DisplayValue);
}
this._var.colAttrs.__filtered = true;
this._refreshSource();
@ -1268,7 +1324,8 @@ export class Grid {
content.style.top = `${rowHeight}px`;
this._set(col.key, 'filterSource', array);
for (let item of array) {
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(item.Value ?? item);
const v = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item;
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(v);
}
if (array.length > 12) {
array = array.slice(0, 12);
@ -1282,7 +1339,7 @@ export class Grid {
const div = createElement('div', 'filter-item');
div.appendChild(createCheckbox({
checked: item.__checked,
label: item?.DisplayValue ?? item,
label: Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item,
onchange: e => {
item.__checked = e.target.checked;
all.querySelector('input').checked = ![...content.querySelectorAll('input')].some(i => !i.checked);
@ -1333,7 +1390,7 @@ export class Grid {
const cx = getClientX(e);
const clearEvents = attr => {
for (let event of ['mousemove', 'mouseup']) {
if (attr.hasOwnProperty(event)) {
if (Object.prototype.hasOwnProperty.call(attr, event)) {
window.removeEventListener(event, attr[event]);
delete attr[event];
}
@ -1346,20 +1403,28 @@ export class Grid {
clearEvents(attr);
}
attr.dragging = true;
const offsetLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
const scrollLeft = this._var.el.scrollLeft;
const draggerCellLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
// const gridScrollLeft = this._var.el.scrollLeft;
let p = this._var.el;
let gridLeftFromWindow = p.offsetLeft;
while ((p = p.offsetParent) != null) {
gridLeftFromWindow += p.offsetLeft + p.clientLeft;
}
const mouse = cx - e.currentTarget.offsetLeft + this._var.el.scrollLeft - gridLeftFromWindow;
const dragmove = e => {
const cx2 = getClientX(e);
const offset = cx2 - cx;
let pos = attr.offset;
let dragging;
if (pos == null && (offset > MiniDragOffset || offset < -MiniDragOffset)) {
dragging = true;
if (pos == null) {
if (offset > MiniDragOffset || offset < -MiniDragOffset) {
dragging = true;
}
} else if (pos !== offset) {
dragging = true;
}
if (dragging) {
this._changingColumnOrder(index, offset, cx2, offsetLeft, scrollLeft);
this._changingColumnOrder(index, offset, mouse, draggerCellLeft);
attr.offset = offset;
}
};
@ -1386,7 +1451,7 @@ export class Grid {
const window = this.window ?? global;
const clearEvents = attr => {
for (let event of ['mousemove', 'mouseup']) {
if (attr.hasOwnProperty(event)) {
if (Object.prototype.hasOwnProperty.call(attr, event)) {
window.removeEventListener(event, attr[event]);
delete attr[event];
}
@ -1648,7 +1713,7 @@ export class Grid {
if (enabled !== false) {
const val = item[col.key];
let oldValue;
if (val?.Value != null) {
if (val != null && Object.prototype.hasOwnProperty.call(val, 'Value') != null) {
oldValue = val.Value;
val.Value = value;
} else {