diff --git a/packages/abc/st/demo/row-click.md b/packages/abc/st/demo/row-click.md
index 882af536a..adc8fe9f2 100644
--- a/packages/abc/st/demo/row-click.md
+++ b/packages/abc/st/demo/row-click.md
@@ -19,15 +19,23 @@ Use `(change)` to implement click line callback, because DOM events can't distin
```ts
import { Component } from '@angular/core';
-import { STChange, STColumn } from '@delon/abc/st';
+
+import { STChange, STClickRowClassNameType, STColumn } from '@delon/abc/st';
@Component({
selector: 'app-demo',
- template: ` `,
+ template: ` `
})
export class DemoComponent {
url = `/users?results=3`;
params = { a: 1, b: 2 };
+ clickRowClassName: STClickRowClassNameType = { exclusive: true, fn: () => 'text-error' };
columns: STColumn[] = [
{ title: '编号', index: 'id' },
{ title: '邮箱', index: 'email' },
@@ -38,10 +46,10 @@ export class DemoComponent {
{
text: 'btn',
type: 'link',
- click: e => console.log('btn click', e),
- },
- ],
- },
+ click: e => console.log('btn click', e)
+ }
+ ]
+ }
];
_click(e: STChange): void {
diff --git a/packages/abc/st/index.en-US.md b/packages/abc/st/index.en-US.md
index 488619480..791ee5cae 100644
--- a/packages/abc/st/index.en-US.md
+++ b/packages/abc/st/index.en-US.md
@@ -62,6 +62,7 @@ When an exception is thrown when parsing column data, *INVALID DATA* will be for
| `[size]` | Size of table | `'small','middle','default'` | `'default'` | ✅ |
| `[widthMode]` | Set the table width mode | `STWidthMode` | - | ✅ |
| `[rowClassName]` | Row class name of table | `(record: STData, index: number) => string` | - | ✅ |
+| `[clickRowClassName]` | Row class name of click the row | `string, STClickRowClassNameType` | - | ✅ |
| `[loading]` | Loading status of table, when specifying `null` is controlled by st | `boolean | null` | `null` | - |
| `[loadingIndicator]` | The spinning indicator | `TemplateRef` | - | ✅ |
| `[loadingDelay]` | Specifies a delay in milliseconds for loading state (prevent flush) | `number` | `0` | ✅ |
diff --git a/packages/abc/st/index.zh-CN.md b/packages/abc/st/index.zh-CN.md
index b5df28bd2..9b0045518 100644
--- a/packages/abc/st/index.zh-CN.md
+++ b/packages/abc/st/index.zh-CN.md
@@ -62,6 +62,7 @@ module: import { STModule } from '@delon/abc/st';
| `[size]` | table大小 | `'small','middle','default'` | `'default'` | ✅ |
| `[widthMode]` | 设置表格宽度模式 | `STWidthMode` | - | ✅ |
| `[rowClassName]` | 表格行的类名 | `(record: STData, index: number) => string` | - | ✅ |
+| `[clickRowClassName]` | 点击行切换类名 | `string, STClickRowClassNameType` | - | ✅ |
| `[loading]` | 页面是否加载中,当指定 `null` 由 st 受控 | `boolean | null` | `null` | - |
| `[loadingIndicator]` | 加载指示符 | `TemplateRef` | - | ✅ |
| `[loadingDelay]` | 延迟显示加载效果的时间(防止闪烁) | `number` | `0` | ✅ |
diff --git a/packages/abc/st/st.component.ts b/packages/abc/st/st.component.ts
index 8b342b7ba..6981f46c4 100644
--- a/packages/abc/st/st.component.ts
+++ b/packages/abc/st/st.component.ts
@@ -50,6 +50,8 @@ import { ST_DEFAULT_CONFIG } from './st.config';
import {
STChange,
STChangeType,
+ STClickRowClassName,
+ STClickRowClassNameType,
STColumn,
STColumnButton,
STColumnFilterMenu,
@@ -191,6 +193,7 @@ export class STComponent implements AfterViewInit, OnChanges, OnDestroy {
};
}
@Input() rowClassName: STRowClassName;
+ @Input() clickRowClassName?: STClickRowClassName | null;
@Input()
set widthMode(value: STWidthMode) {
this._widthMode = { ...this.cog.widthMode, ...value };
@@ -512,7 +515,8 @@ export class STComponent implements AfterViewInit, OnChanges, OnDestroy {
this._data.filter(i => i !== item).forEach(i => (i.expand = false));
}
_rowClick(e: Event, item: STData, index: number): void {
- if ((e.target as HTMLElement).nodeName === 'INPUT') return;
+ const el = e.target as HTMLElement;
+ if (el.nodeName === 'INPUT') return;
const { expand, expandRowByClick, rowClickTime } = this;
if (!!expand && item.showExpand !== false && expandRowByClick) {
item.expand = !item.expand;
@@ -525,6 +529,7 @@ export class STComponent implements AfterViewInit, OnChanges, OnDestroy {
setTimeout(() => {
const data = { e, item, index };
if (this.rowClickCount === 1) {
+ this._clickRowClassName(el, item, index);
this.changeEmit('click', data);
} else {
this.changeEmit('dblClick', data);
@@ -533,6 +538,25 @@ export class STComponent implements AfterViewInit, OnChanges, OnDestroy {
}, rowClickTime);
}
+ private _clickRowClassName(el: HTMLElement, item: STData, index: number): void {
+ const cr = this.clickRowClassName;
+ if (cr == null) return;
+ const config = {
+ exclusive: false,
+ ...(typeof cr === 'string' ? { fn: () => cr } : cr)
+ } as STClickRowClassNameType;
+ const className = config.fn(item, index);
+ const trEl = el.closest('tr') as HTMLElement;
+ if (config.exclusive) {
+ trEl.parentElement!!.querySelectorAll('tr').forEach((a: HTMLElement) => a.classList.remove(className));
+ }
+ if (trEl.classList.contains(className)) {
+ trEl.classList.remove(className);
+ } else {
+ trEl.classList.add(className);
+ }
+ }
+
_expandChange(item: STData, expand: boolean): void {
item.expand = expand;
this.closeOtherExpand(item);
diff --git a/packages/abc/st/st.interfaces.ts b/packages/abc/st/st.interfaces.ts
index 3e2c84e4d..d0d676868 100644
--- a/packages/abc/st/st.interfaces.ts
+++ b/packages/abc/st/st.interfaces.ts
@@ -1080,6 +1080,16 @@ export interface STError {
}
export type STRowClassName = (record: T, index: number) => string;
+export type STClickRowClassName = string | STClickRowClassNameType;
+export interface STClickRowClassNameType {
+ fn: (record: T, index: number) => string;
+ /**
+ * Whether mutually exclusive, default: `false`
+ *
+ * 是否互斥,默认:`false`
+ */
+ exclusive?: boolean;
+}
export interface STColumnGroupType {
column: STColumn;
diff --git a/packages/abc/st/test/st.spec.ts b/packages/abc/st/test/st.spec.ts
index 0fe6d5e9e..19c997874 100644
--- a/packages/abc/st/test/st.spec.ts
+++ b/packages/abc/st/test/st.spec.ts
@@ -35,6 +35,8 @@ import { STComponent } from '../st.component';
import {
STChange,
STChangeType,
+ STClickRowClassName,
+ STClickRowClassNameType,
STColumn,
STColumnBadge,
STColumnFilter,
@@ -1371,6 +1373,59 @@ describe('abc: st', () => {
el.click();
page.cd().expectChangeType('click', false);
}));
+ describe('clickRowClassName', () => {
+ it('should be null', fakeAsync(() => {
+ context.clickRowClassName = null;
+ page.cd();
+ const trEl = (page.getCell() as HTMLElement).closest('tr') as HTMLElement;
+ const oldClassName = trEl.classList.value;
+ trEl.click();
+ page.cd(100);
+ expect(trEl.classList.value).toBe(oldClassName);
+ }));
+ it('should be string', fakeAsync(() => {
+ context.clickRowClassName = 'aa';
+ page.cd();
+ const trEl = (page.getCell() as HTMLElement).closest('tr') as HTMLElement;
+ expect(trEl.classList).not.toContain('aa');
+ trEl.click();
+ page.cd(100);
+ expect(trEl.classList).toContain('aa');
+ trEl.click();
+ page.cd(100);
+ expect(trEl.classList).not.toContain('aa');
+ }));
+ it('should be exclusive with false', fakeAsync(() => {
+ context.clickRowClassName = { exclusive: false, fn: () => 'bb' } as STClickRowClassNameType;
+ page.cd();
+ [1, 2].forEach(idx => {
+ const trEl = (page.getCell(idx) as HTMLElement).closest('tr') as HTMLElement;
+ expect(trEl.classList).not.toContain('bb');
+ trEl.click();
+ page.cd(100);
+ expect(trEl.classList).toContain('bb');
+ });
+ const len = ((page.getCell() as HTMLElement).closest('tbody') as HTMLElement).querySelectorAll(
+ 'tr.bb'
+ ).length;
+ expect(len).toBe(2);
+ }));
+ it('should be exclusive with true', fakeAsync(() => {
+ context.clickRowClassName = { exclusive: true, fn: () => 'bb' } as STClickRowClassNameType;
+ page.cd();
+ [1, 2].forEach(idx => {
+ const trEl = (page.getCell(idx) as HTMLElement).closest('tr') as HTMLElement;
+ expect(trEl.classList).not.toContain('bb');
+ trEl.click();
+ page.cd(100);
+ expect(trEl.classList).toContain('bb');
+ });
+ const len = ((page.getCell() as HTMLElement).closest('tbody') as HTMLElement).querySelectorAll(
+ 'tr.bb'
+ ).length;
+ expect(len).toBe(1);
+ }));
+ });
});
describe('[public method]', () => {
describe('#load', () => {
@@ -2178,6 +2233,7 @@ describe('abc: st', () => {
[noResult]="noResult"
[widthConfig]="widthConfig"
[rowClickTime]="rowClickTime"
+ [clickRowClassName]="clickRowClassName"
[showHeader]="showHeader"
[contextmenu]="contextmenu"
[customRequest]="customRequest"
@@ -2207,6 +2263,7 @@ class TestComponent {
noResult = 'noResult';
widthConfig: string[] = [];
rowClickTime = 200;
+ clickRowClassName?: STClickRowClassName | null = 'text-error';
responsive = false;
responsiveHideHeaderFooter = false;
expandRowByClick = false;