5.5.12. Подключаемые фабрики компонентов
Механизм подключаемых фабрик компонентов расширяет процедуру генерации компонентов и позволяет создавать различные поля редактирования в FieldGroup, Table и DataGrid. Это означает, что компоненты приложения или сам ваш проект могут предоставлять собственные стратегии, которые будут создавать нестандартные компоненты и/или поддерживать кастомные типы данных.
Для того, чтобы воспользоваться данным механизмом, следует использовать метод ComponentsFactory.createComponent(ComponentGenerationContext)
. Он работает следующим образом:
-
Пытается найти все реализации интерфейса
ComponentGenerationStrategy
. Если как минимум одна реализация существует:-
Обходит все реализации в соответствии с интерфейсом
org.springframework.core.Ordered
. -
Возвращается первый созданный не нулевой компонент.
-
Реализации интерфейса ComponentGenerationStrategy
используются при создании UI компонентов. Проект может содержать любое количество таких стратегий.
ComponentGenerationContext
- класс, содержащий следующую информацию, которая может быть использована при создании компонента:
-
metaClass
- задает сущность, для которой создается компонент. -
property
- задает атрибут сущности, для которой создается компонент. -
datasource
- источник данных, который может быть связан с компонентом. -
optionsDatasource
- источник данных, который может быть связан с компонентом для показа опций. -
xmlDescriptor
- XML дескриптор с дополнительной информацией, в случае, если компонент описан в XML дескрипторе. -
componentClass
- класс компонента для которого должен быть создан компонент (например,Table
,FieldGroup
,DataGrid
).
В платформе существуют две стандартных реализации ComponentGenerationStrategy
:
-
DefaultComponentGenerationStrategy
- используется для создания компонентов в соответствии с переданнымComponentGenerationContext
. Имеет значение order равноеComponentGenerationStrategy.LOWEST_PLATFORM_PRECEDENCE
(1000). -
DataGridEditorComponentGenerationStrategy
- используется для создания компонентов для DataGrid Editor в соответствии с переданнымComponentGenerationContext
. Имеет значение order равноеComponentGenerationStrategy.HIGHEST_PLATFORM_PRECEDENCE + 30
(130).
Пример ниже показывает, как заменить стандартную генерацию компонента в FieldGroup
для определенного атрибута некоторой сущности.
@Component(SalesComponentGenerationStrategy.NAME)
public class SalesComponentGenerationStrategy implements ComponentGenerationStrategy, Ordered {
public static final String NAME = "sales_SalesComponentGenerationStrategy";
@Inject
private ComponentsFactory componentsFactory;
@Inject
private Metadata metadata;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaClass orderMetaClass = metadata.getClassNN(Order.class);
// Check the specific field of the Order entity
// and that the component is created for the FieldGroup component
if (orderMetaClass.equals(context.getMetaClass())
&& "date".equals(property)
&& context.getComponentClass() != null
&& FieldGroup.class.isAssignableFrom(context.getComponentClass())) {
DatePicker datePicker = componentsFactory.createComponent(DatePicker.class);
Datasource datasource = context.getDatasource();
if (datasource != null) {
datePicker.setDatasource(datasource, property);
}
return datePicker;
}
return null;
}
@Override
public int getOrder() {
return 50;
}
}
Warning
|
Обратите внимание, что переопределение существующих стратегий генерации компонентов может приводить к ошибкам в случае изменения типа возвращаемого компонента, поскольку некоторые контроллеры экрана могут иметь код, ожидающий определенный тип компонента. Например, в случае использования вышеприведенной стратегии, следующая инжекция приведет к исключению:
Если вы попытаетесь открыть такой экран, то получите следующее исключение: IllegalArgumentException: Can not set com.haulmont.cuba.gui.components.DateField field com.company.sales.web.order.OrderEdit.dateField to com.haulmont.cuba.web.gui.components.WebDatePicker |
Пример ниже показывает, как определить ComponentGenerationStrategy
для специализированного datatype.
@Order(100)
@Component(ColorComponentGenerationStrategy.NAME)
public class ColorComponentGenerationStrategy implements ComponentGenerationStrategy {
public static final String NAME = "colordatatype_ColorComponentGenerationStrategy";
@Inject
private ComponentsFactory componentsFactory;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaPropertyPath mpp = resolveMetaPropertyPath(context.getMetaClass(), property);
if (mpp != null) {
Range mppRange = mpp.getRange();
if (mppRange.isDatatype()
&& ((Datatype) mppRange.asDatatype()) instanceof ColorDatatype) {
ColorPicker colorPicker = componentsFactory.createComponent(ColorPicker.class);
colorPicker.setDefaultCaptionEnabled(true);
Datasource datasource = context.getDatasource();
if (datasource != null) {
colorPicker.setDatasource(datasource, property);
}
return colorPicker;
}
}
return null;
}
protected MetaPropertyPath resolveMetaPropertyPath(MetaClass metaClass, String property) {
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
}
return mpp;
}
}