Pluggable Component Factories
The pluggable component factories mechanism extends the standard component creation procedure and allows you to create different edit fields in Form, Table and DataGrid. It means that application components or your project itself can provide custom strategies that will create non-standard components and/or support custom data types.
An entry point to the mechanism is the UiComponentsGenerator.generate(ComponentGenerationContext)
method. First, it tries to find ComponentGenerationStrategy
implementations. If at least one strategy exists, then it iterates over strategies according to the org.springframework.core.Ordered
interface and returns the first created not null
component.
ComponentGenerationStrategy
implementations are used to create UI components. A project can contain any number of such strategies.
ComponentGenerationContext
is a class which stores the following information that can be used when creating a component:
-
metaClass
- defines the entity for which the component is created. -
property
- defines the entity attribute for which the component is created. -
valueSource
- a value source that can be used to create the component. -
options
- an options object that can be used to show options. -
xmlDescriptor
- an XML descriptor which contains additional information, in case the component is declared in an XML descriptor. -
targetClass
- a target class for which a component is created, for example,Form
,Table
,DataGrid
.
There are two built-in component strategies:
-
DefaultComponentGenerationStrategy
is used to create a component according to the givenComponentGenerationContext
object. Has the order valueJmixOrder.LOWEST_PLATFORM_PRECEDENCE
(1000). Higher values are interpreted as lower priority, the lowest value has the highest priority, same order values will result in arbitrary sort positions for the affected objects. -
CustomDatatypesComponentGenerationStrategy
is intended for generating a default field corresponding to a datatype for which other generation strategies didn’t create a field. For instance, when a datatype is custom and doesn’t match any type for which theDefaultComponentGenerationStrategy
creates fields. Has the order valueInteger.MAX_VALUE
(0x7fffffff).
The sample below shows how to replace the default Form
field generation for a certain attribute of a specific entity.
@org.springframework.stereotype.Component("sample_SalesComponentGenerationStrategy")
public class SalesComponentGenerationStrategy implements ComponentGenerationStrategy, Ordered {
@Inject
private UiComponents uiComponents;
@Inject
private Metadata metadata;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaClass orderMetaClass = metadata.getClass(Order.class);
if (orderMetaClass.equals(context.getMetaClass())
&& "date".equals(property) (1)
&& context.getClass() != null
&& Form.class.isAssignableFrom(context.getClass())) { (2)
DatePicker<Date> datePicker = uiComponents.create(DatePicker.TYPE_DATE); (3)
ValueSource valueSource = context.getValueSource();
if (valueSource != null) {
datePicker.setValueSource(valueSource); (4)
}
return datePicker;
}
return null;
}
@Override
public int getOrder() {
return 50; (5)
}
}
1 | Checks the specific field of the Order entity. |
2 | Checks that the component is created for the Form component. |
3 | Creates the specific DatePicker component. |
4 | Binds the component to a data source. |
5 | Gets the order value of this object. |
The sample below shows how to define a ComponentGenerationStrategy
for specific datatype.
@Order(100)
@org.springframework.stereotype.Component("sample_ColorComponentGenerationStrategy")
public class ColorComponentGenerationStrategy implements ComponentGenerationStrategy {
@Inject
private UiComponents uiComponents;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaPropertyPath mpp = context.getMetaClass().getPropertyPath(property);
if (mpp != null) {
Range mppRange = mpp.getRange();
if (mppRange.isDatatype()
&& (Datatype) mppRange.asDatatype() instanceof ColorDatatype) {
ColorPicker colorPicker = uiComponents.create(ColorPicker.class);
colorPicker.setDefaultCaptionEnabled(true);
ValueSource valueSource = context.getValueSource();
if (valueSource != null) {
colorPicker.setValueSource(valueSource);
}
return colorPicker;
}
}
return null;
}
}