Изменить цвет строки по кнопке
В данном примере создаётся новая колонка таблицы грида. В новую колонку добавляется элемент, нажатие на который открывает диалог выбора цвета. При изменении цвета в диалоге, будет изменяться фон строки, в которой находится ячейка.
extensionManager.registerExtension({ (1)
name: "BackgroundRows",
version: "6.1",
initialize() {
app.folderPluginProvider.addFactory(new BackgroundRowsPluginFactory());
},
})
1 | Регистрация расширения позволяет корректно установить все обработчики событий, сервисы и прочие сущности web-приложения. |
Создание кнопки, открывающей диалог выбора цвета:
export interface IBackgroundRowsButton extends PropsWithChildren<ICompositionPluginProps<"TableCell", ICellData, $BackgroundRows>> {
}
export function BackgroundRowsButton (props: IBackgroundRowsButton) { (1)
const { services: { backgroundRows }, data: { row } } = props.composition;
const [ color, setColor ] = useState( backgroundRows.$rows.getState()[row.entityId] ?? "#ffffff" ); (2)
const changeColor = (ev: ChangeEvent<HTMLInputElement>) => {
backgroundRows.setBackground({ id: row.entityId, color: ev.target.value }); (3)
setColor(ev.target.value); (4)
};
const click = (ev: React.MouseEvent) => {
ev.stopPropagation(); (5)
};
if (!getRowLoaded(row).loaded) { (6)
return <></>
}
return (
<input
className="background-rows__button"
type="color"
value={color}
onClick={click}
onChange={changeColor} />
)
};
1 | Предоставляет возможность отобразить палитру цветов |
2 | Исходный цвет: белый. |
3 | Обновляем хранилище. |
4 | Обновляем локальное состояние input с type=color . |
5 | Прекращает дальнейшую передачу текущего события. |
6 | Если строка ещё не загружена, то ничего не показываем. |
Создаём сервис, который будет хранить и обновлять цвет строки:
export class BackgroundRowsService implements IBackgroundRowsService {
$rows: Store<IBackgroundRows>;
setBackground: Event<IBackgroundRow>;
constructor() {
const domain = createDomain("BackgroundRows"); (1)
this.setBackground = domain.event("setBackground");
this.$rows = domain.store({}, { name: "$rows" })
.on(this.setBackground, (store, background) => ({...store, [background.id]: background.color }));
}
}
1 | Инициализируем сущности необходимые для хранения и обновления хранилища. |
Добавляем интерфейс сервиса:
export interface IBackgroundRows {
[id: string]: string;
}
export interface IBackgroundRow {
id: string;
color: string;
}
export interface IBackgroundRowsService { (1)
readonly $rows: Store<IBackgroundRows>;
setBackground: Event<IBackgroundRow>;
}
1 | Интерфейс сервиса. |
Инициализируем сущности, необходимые для хранения и обновления хранилища:
export class BackgroundRowsService implements IBackgroundRowsService {
$rows: Store<IBackgroundRows>;
setBackground: Event<IBackgroundRow>;
constructor() {
const domain = createDomain("BackgroundRows");
this.setBackground = domain.event("setBackground");
this.$rows = domain.store({}, { name: "$rows" })
.on(this.setBackground, (store, background) => ({...store, [background.id]: background.color }));
}
}
Подключаем плагины грида:
export class BackgroundRowsPluginFactory implements IFolderPluginFactory {
id: string = "BackgroundRowsPluginFactory";
getDataLoadingPlugins(): IFolderDataLoadingPlugin[] {
return [
new BackgroundRowsResponseResolver()
]
}
getTablePlugins(): ITablePlugins[] {
return [
BackgroundRowsPlugins
];
}
}
Добавляем новую колонку для элемента переключения цвета:
export class BackgroundRowsResponseResolver implements IFolderDataLoadingPlugin {
id: string = "BackgroundRowsResponseResolver";
description: string = "Добавляет новую колонку.";
order: PluginOrder = PluginOrder.Normal;
async resolveResponse(data: ITableData, response: GenModels.GridViewModelEx): Promise<void | ResponseResolveResult> { (1)
if (data.columns.length && !data.columns.find(x => x.id == BackgroundRowsColumnId)) { (2)
const backgroundRowsColumn = {
id: BackgroundRowsColumnId, (3)
name: "Фон строки", (4)
} as IColumn;
data.columns.push(backgroundRowsColumn);
}
}
}
1 | Вызывается после каждого ответа загрузки данных таблицы. |
2 | Сделаем проверку на существование столбцов в таблице, а также проверим не был ли добавлен столбец, который мы хотим создать. |
3 | Уникальный идентификатор столбца. |
4 | Отображаемое название столбца. |
Настраиваем элемент в ячейке:
export const BackgroundRowsColumnId = "backgroundRows";
export const BackgroundRowsFeature = "BackgroundRowsFeature";
export const BackgroundRowsServiceProvider: TablePlugins.ServiceProvider<$BackgroundRows> = {
name: "BackgroundRowsServiceProvider",
description: "Добавляет сервис $BackgroundRows.",
feature: BackgroundRowsFeature,
composition: TableCompositionNames.Root,
addServices: (composition) => {
if (!composition.services.backgroundRows) { (1)
composition.services.backgroundRows = new BackgroundRowsService();
}
}
};
export const BackgroundRowsCellButtonPlugin: TablePlugins.Cell.Component<$BackgroundRows> = {
name: "BackgroundRowsCellButtonPlugin",
description: "Отображает кнопку изменения фона строки.",
feature: BackgroundRowsFeature,
composition: TableCompositionNames.TableCell,
shouldRender: (composition) => composition.data.column.id == BackgroundRowsColumnId, (2)
component: BackgroundRowsButton (3)
};
export const BackgroundRowsMountEffect: TablePlugins.Row.MountEffect<$BackgroundRows> = {
name: "BackgroundRowsMountEffect",
description: "Обновляет композицию при изменении $rows",
feature: BackgroundRowsFeature,
composition: TableCompositionNames.TableRow,
compositionDidMount: (composition) => { (4)
const { backgroundRows } = composition.services;
const optimalUpdate = throttle({ source: backgroundRows.$rows, timeout: 100 }); (5)
const update = optimalUpdate.watch(() => composition.update()); (6)
return () => update.unsubscribe(); (7)
}
};
export const BackgroundRowDecorator: TablePlugins.Row.Decorator<$BackgroundRows> = {
name: "BackgroundRowDecorator",
description: "Изменяет фон строки.",
feature: BackgroundRowsFeature,
composition: TableCompositionNames.TableRow,
jsxDecorator: (node, composition) => { (8)
const { services, data } = composition;
const backgroundRows = services.backgroundRows.$rows.getState(); (9)
return decorate(node, { style: { background: backgroundRows[data.row.entityId] }}); (10)
}
};
export const BackgroundRowsPlugins: ITablePlugins = {
serviceProviders: [ BackgroundRowsServiceProvider ],
row: {
mountEffects: [ BackgroundRowsMountEffect ],
containerDecorators: [ BackgroundRowDecorator ]
},
cell: {
content: [ BackgroundRowsCellButtonPlugin ]
}
};
1 | Поскольку addServices вызывается при каждой отрисовке, сделаем проверку на существование сервиса, который хотим добавить. |
2 | Компонент будет отображён, если условие правдиво. |
3 | Компонент, который будет отображён в ячейке добавленной колонки. |
4 | Вызывается при монтировании компоненты. |
5 | Поскольку хранилище backgroundRow.$rows может меняться достаточно быстро (зависит от скорости изменения цвета в палитре), необходимо установить ограничение обновления композиции.
В данном случае, |
6 | Когда сработает событие, композиция таблицы будет обновлена. |
7 | Отписка от события, когда компонент будет размонтирован. |
8 | Метод, с помощью которого появляется возможность декорирования ReactNode . |
9 | Получаем хранилище, которое содержит информацию о цвете фона строк. |
10 | В данном методе вторым аргументом является объект свойств ReactNode , как в React.createElement .
В данном случае, если хранилище содержит информацию о фоне строки, она будет применена, в противном случае стиль не применится. |