Skip to content

Dictionary

Dictionary is a component that allows to select single value from dropdown.

Tip

Use for dictionaries or slowly-growing entities, e.g. no more than 1000 values (all values are loaded in memory). Otherwise, use inlinePickList

Basics

Live Sample · GitHub

How does it look?

img_list.gif

img_info.png

img_form.gif

How to add?

Example
  • Step1 Create Enum. Best practice: storing enum name in the Database and using a separate field for displayed UI values
    @Getter
    @AllArgsConstructor
    public enum CustomFieldEnum {
        BELGOROD("Belgorod region"),
        BRYANSK("Bryansk region"),
        VLADIMIR("Vladimir region"),
        VORONEZH("Voronezh region"),
        IVANOVO("Ivanovo region"),
        KALUGA("Kaluga region"),
        KOSTROMA("Kostroma region"),
        KURSK("Kursk region"),
        MOSCOW("Moscow region"),
        ORYOL("Oryol region"),
        RYAZAN("Ryazan region"),
        SMOLENSK("Smolensk region"),
        TAMBOV("Tambov region"),
        TVER("Tver region");
    
        @JsonValue
        private final String value;
    
        public static CustomFieldEnum getByValue(@NonNull String value) {
            return Arrays.stream(CustomFieldEnum.values())
                    .filter(enm -> Objects.equals(enm.getValue(), value))
                    .findFirst()
                    .orElse(null);
        }
    }
    
  • Step2 Add Enum field to corresponding BaseEntity.
    @Entity
    @Getter
    @Setter
    @NoArgsConstructor
    public class MyEntity extends BaseEntity {

        @Enumerated(value = EnumType.STRING)
        @Column
        private CustomFieldEnum customField;

    }
  • Step3 Add Enum field to corresponding DataResponseDTO.
    @Getter
    @Setter
    @NoArgsConstructor
    public class MyExampleDTO extends DataResponseDTO {

        @SearchParameter(name = "customField", provider = EnumValueProvider.class)
        private CustomFieldEnum customField;

        public MyExampleDTO(MyEntity entity) {
            this.id = entity.getId().toString();
            this.customField = entity.getCustomField();
        }

    }
  • Step4 Add fields.setEnumValues to corresponding FieldMetaBuilder.
    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnumValues(MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.setEnabled(MyExampleDTO_.customField);
    }
  • Step5 Add to .widget.json.
{
  "name": "MyExampleList",
  "title": "List title",
  "type": "List",
  "bc": "myExampleBc",
  "fields": [
    {
      "title": "Custom Field",
      "key": "customField",
      "type": "dictionary"
    }
  ]
}
  • Step5 Add to .widget.json.
{
  "name": "MyExampleInfo",
  "title": "Info title",
  "type": "Info",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}
  • Step5 Add to .widget.json.
{
  "name": "MyExampleForm",
  "title": "Form title",
  "type": "Form",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}
  • Step 1. LOV Create LOV

    • Step 1.1 Add type LOV to CXBOX-DICTIONARY_TYPE.csv.

      ID;TYPE;TYPE_DESC
      200;REGIONS;Regions
      
    • Step 1.2 Add description and value LOV to CXBOX-DICTIONARY_ITEM.csv.

      "300";200;"REGIONS";"MOSCOW";"Moscow";true;0;null
      "301";200;"REGIONS";"SAINT PETERBURG";"St. Petersburg";true;1;null
      "302";200;"REGIONS";"KOSTROMA";"Kostroma";true;2;null
      "303";200;"REGIONS";"SYKTYVKAR";"Syktyvkar";true;3;null
      
    • Step 1.3 Add corresponding launguage to database change management DICTIONARY_ITEM_TR.

      <changeSet id="ADD LANGUAGE DICTIONARY_ITEM_TR" author="initial">
        <sql>
          insert into DICTIONARY_ITEM_TR (ID, LANGUAGE, VALUE)
          select ID, 'en' as LANGUAGE, VALUE as VALUE
          from DICTIONARY_ITEM;
        </sql>
        <sql>
          insert into DICTIONARY_ITEM_TR (ID, LANGUAGE, VALUE)
          select ID, 'ru' as LANGUAGE, VALUE as VALUE
          from DICTIONARY_ITEM;
        </sql>
      </changeSet>
      
    • Step 1.4 Add in project AdministeredDictionary

      @Target(FIELD)
      @Retention(RUNTIME)
      @BaseLov(type = AdministeredDictionaryType.class)
      public @interface AdministeredDictionary {
      
          AdministeredDictionaryType value();
      
      }
      
    • Step 1.5 Add in project AdministeredDictionaryType

      @Getter
      @RequiredArgsConstructor
      public enum AdministeredDictionaryType implements Serializable, IDictionaryType {
      
          @Override
          public LOV lookupName(String val) {
              return dictionary().lookupName(val, this);
          }
      
          @Override
          public String lookupValue(LOV lov) {
              return dictionary().lookupValue(lov, this);
          }
      
          @Override
          public String getName() {
              return name();
          }
      
          public boolean containsKey(String key) {
              return dictionary().containsKey(key, this);
          }
      
      }
      
    • Step 1.6 Add LOV (REGIONS) in AdministeredDictionaryType

      @Getter
      @RequiredArgsConstructor
      public enum AdministeredDictionaryType implements Serializable, IDictionaryType {
      
          REGIONS;
      
          @Override
          public LOV lookupName(String val) {
              return dictionary().lookupName(val, this);
          }
      
          @Override
          public String lookupValue(LOV lov) {
              return dictionary().lookupValue(lov, this);
          }
      
          @Override
          public String getName() {
              return name();
          }
      
          public boolean containsKey(String key) {
              return dictionary().containsKey(key, this);
          }
      
      }
      

  • Step2 Add LOV field to corresponding BaseEntity.

@Entity
@Getter
@Setter
@NoArgsConstructor
public class MyEntity extends BaseEntity {

    @Column
    private LOV customField;

}
  • Step3Add String field to corresponding DataResponseDTO.
@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {

    @SearchParameter(provider = LovValueProvider.class)
    @AdministeredDictionary(REGIONS)
    private String customField;

    public MyExampleDTO(MyEntity entity) {
        this.id = entity.getId().toString();
        this.customField = REGIONS.lookupValue(entity.getCustomField());
    }

}
  • Step4 Add fields.setDictionaryTypeWithAllValues to corresponding FieldMetaBuilder.
    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnabled(MyExampleDTO_.customField);
        fields.setDictionaryTypeWithAllValues(MyExampleDTO_.customField, REGIONS);

    }
  • Step5 Add to .widget.json.
    {
      "name": "MyExampleInfo",
      "title": "Info title",
      "type": "Info",
      "bc": "myExampleBc",
      "fields": [
        {
          "label": "Custom Field",
          "key": "customField",
          "type": "dictionary"
        }
      ],
      "options": {
        "layout": {
          "rows": [
            {
              "cols": [
                {
                  "fieldKey": "customField",
                  "span": 12
                }
              ]
            }
          ]
        }
      }
    }
  • Step5 Add to .widget.json.
{
  "name": "MyExampleInfo",
  "title": "Info title",
  "type": "Info",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}
  • Step5 Add to .widget.json.
{
  "name": "MyExampleForm",
  "title": "Form title",
  "type": "Form",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}

Placeholder

Live Sample · GitHub

Placeholder allows you to provide a concise hint, guiding users on the expected value. This hint is displayed before any user input. It can be calculated based on business logic of application

How does it look?

img_plchldr_list.png

not applicable

img_plchldr_form.png

How to add?

Example

Add fields.setPlaceholder to corresponding FieldMetaBuilder.

    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnumValues(MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.setEnabled(MyExampleDTO_.customField);
        fields.setPlaceholder(MyExampleDTO_.customField, "Placeholder text");
    }

Works for List.

not applicable

Works for Form.

Color

Color allows you to specify a field color. It can be calculated based on business logic of application

Calculated color: Live Sample · GitHub

Constant color: Live Sample · GitHub

How does it look?

img_color_list.png

img_color_info.png

not applicable

How to add?

Example

Step 1 Add custom field for color to corresponding DataResponseDTO. The field can contain a HEX color or be null.

@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {

    @SearchParameter(name = "customField", provider = EnumValueProvider.class)
    private CustomFieldEnum customField;

    private String customFieldColor;

    public MyExampleDTO(MyEntity entity) {
        this.id = entity.getId().toString();
        this.customField = entity.getCustomField();
        this.customFieldColor = "#edaa";
    }

}

Step 2 Add "bgColorKey" : custom field for color to .widget.json.

{
  "name": "MyExampleList",
  "title": "List title",
  "type": "List",
  "bc": "myExampleBc",
  "fields": [
    {
      "title": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "bgColorKey": "customFieldColor"
    }
  ]
}

Step 2 Add "bgColorKey" : custom field for color to .widget.json.

{
  "name": "MyExampleInfo",
  "title": "Info title",
  "type": "Info",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "bgColorKey": "customFieldColor"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}

not applicable

Add "bgColor" : HEX color to .widget.json.

{
  "name": "MyExampleList",
  "title": "List title",
  "type": "List",
  "bc": "myExampleBc",
  "fields": [
    {
      "title": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "bgColor": "#edaa"
    }
  ]
}

Add "bgColor" : HEX color to .widget.json.

{
  "name": "MyExampleInfo",
  "title": "Info title",
  "type": "Info",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "bgColor": "#edaa"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}

not applicable

Readonly/Editable

Readonly/Editable indicates whether the field can be edited or not. It can be calculated based on business logic of application

Editable Live Sample · GitHub

Readonly Live Sample · GitHub

How does it look?

img_edit_list.png

not applicable

img_edit_form.png

img_ro_list.png

img_ro_info.png

img_ro_form.png

How to add?

Example

Step1 Add mapping DTO->entity to corresponding VersionAwareResponseService.

    @Override
    protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyEntity entity, MyExampleDTO data,
            BusinessComponent bc) {
        if (data.isFieldChanged(MyExampleDTO_.customField)) {
            entity.setCustomField(data.getCustomField());
        }

        return new ActionResultDTO<>(entityToDto(bc, entity));
    }

Step2 Add fields.setEnabled to corresponding FieldMetaBuilder.

    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnumValues(MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.setEnabled(MyExampleDTO_.customField);
    }

Works for List.

not applicable

Works for Form.

Option 1 Enabled by default.

    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {

    }

Option 2 Not recommended. Property fields.setDisabled() overrides the enabled field if you use after property fields.setEnabled.

Works for List.

Works for Info.

Works for Form.

Filtering

Live Sample · GitHub

Filtering allows you to search data based on criteria. Search uses in operator.

How does it look?

img_filtr_list.png

not applicable

not applicable

How to add?

Example

Step 1 Add @SearchParameter to corresponding DataResponseDTO. (Advanced customization SearchParameter)

@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {

    @SearchParameter(name = "customField", provider = EnumValueProvider.class)
    private CustomFieldEnum customField;

    public MyExampleDTO(MyEntity entity) {
        this.id = entity.getId().toString();
        this.customField = entity.getCustomField();
    }

}

Step 2 Add fields.enableFilter to corresponding FieldMetaBuilder.

    @Override
    public void buildIndependentMeta(FieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription, Long parentId) {
        if (configuration.getForceActiveEnabled()) {
            fields.setForceActive(MyExampleDTO_.customField);
        }
        fields.setEnumFilterValues(fields, MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.enableFilter(MyExampleDTO_.customField);
    }

not applicable

not applicable

Drilldown

Live Sample · GitHub

DrillDown allows you to navigate to another view by simply tapping on it. Target view and other drill-down parts can be calculated based on business logic of application

Also, it optionally allows you to filter data on target view before it will be opened see more DrillDown

How does it look?

img_drilldown_list

img_drilldown_info

not applicable

How to add?

Example

Option 1

Step 1 Add fields.setDrilldown to corresponding FieldMetaBuilder.

    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnumValues(MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.setEnabled(MyExampleDTO_.customField);
        fields.setDrilldown(
                MyExampleDTO_.customField,
                DrillDownType.INNER,
                "/screen/myexample/view/myexampleform/" + PlatformMyExampleController.myExampleBc + "/" + id
        );
    }

Step 2 Add "drillDown": "true" to .widget.json.

{
  "name": "MyExampleList",
  "title": "List title",
  "type": "List",
  "bc": "myExampleBc",
  "fields": [
    {
      "title": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "drillDown": "true"
    }
  ]
}

Option 2 Add "drillDownKey" : custom field to .widget.json. See more Drilldown

Step 2 Add "drillDown": "true" to .widget.json.

{
  "name": "MyExampleInfo",
  "title": "Info title",
  "type": "Info",
  "bc": "myExampleBc",
  "fields": [
    {
      "label": "Custom Field",
      "key": "customField",
      "type": "dictionary",
      "drillDown": "true"
    }
  ],
  "options": {
    "layout": {
      "rows": [
        {
          "cols": [
            {
              "fieldKey": "customField",
              "span": 12
            }
          ]
        }
      ]
    }
  }
}
Option 2 Add "drillDownKey" : custom field to .widget.json. See more Drilldown

not applicable

Advanced customization

Validation

Validation allows you to check any business rules for user-entered value. There are types of validation:

1) Exception:Displays a message to notify users about technical or business errors.

Business Exception: Live Sample · GitHub

Runtime Exception: Live Sample · GitHub

2) Confirm: Presents a dialog with an optional message, requiring user confirmation or cancellation before proceeding.

Live Sample · GitHub

3) Field level validation: shows error next to all fields, that validation failed for

Option 1: Live Sample · GitHub

Option 2: Live Sample · GitHub

How does it look?

img_business_error

img_runtime_error

confirm_form

img_javax_stat_list

not applicable

img_business_error

img_runtime_error

confirm_form

img_javax_stat_form

How to add?

Example

BusinessException describes an error within a business process.

Add BusinessException to corresponding VersionAwareResponseService.

    @Override
    protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyEntity entity, MyExampleDTO data,
                                                             BusinessComponent bc) {
        if (data.isFieldChanged(MyExampleDTO_.customField)) {
            if (data.getCustomField() != null && !CustomFieldEnum.HIGH.getValue().equals(data.getCustomField().getValue())) {
                throw new BusinessException().addPopup(ONLY_HIGH);
            }
            entity.setCustomField(data.getCustomField());
        }
        return new ActionResultDTO<>(entityToDto(bc, entity));
    }

Works for List.

not applicable

Works for Form.

RuntimeException describes technical error within a business process.

Add RuntimeException to corresponding VersionAwareResponseService.

    @Override
    protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyEntity entity, MyExampleDTO data,
            BusinessComponent bc) {
        if (data.isFieldChanged(MyExampleDTO_.customField)) {
            entity.setCustomField(data.getCustomField());
            try {
                //call custom function
                throw new Exception("Error");
            } catch (Exception e) {
                throw new RuntimeException("An unexpected error has occurred.");
            }
        }

        return new ActionResultDTO<>(entityToDto(bc, entity));
    }

Works for List.

not applicable

Works for Form.

Add PreAction.confirm to corresponding VersionAwareResponseService.

    @Override
    public Actions<MyExampleDTO> getActions() {
        return Actions.<MyExampleDTO>builder()
                .newAction()
                .action("save", "save")
                .withPreAction(PreAction.confirm("You want to save the value ?"))
                .add()
                .build();
    }

Works for List.

not applicable

Works for Form.

Add javax.validation to corresponding DataResponseDTO.

Use if:

Requires a simple fields check (javax validation) Add javax.validation to corresponding DataResponseDTO.

@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {

    @SearchParameter(name = "customField", provider = EnumValueProvider.class)
    @NotNull(message = "Custom message about error")
    private CustomFieldEnum customField;

    public MyExampleDTO(MyEntity entity) {
        this.id = entity.getId().toString();
        this.customField = entity.getCustomField();
    }

}

Works for List.

not applicable

Works for Form.

Create сustom service for business logic check.

Use if:

Business logic check required for fields

Step 1 Create сustom method for check.

    private void validateFields(BusinessComponent bc, MyExampleDTO dto) {
        BusinessError.Entity entity = new BusinessError.Entity(bc);
        if (!dto.getCustomField().getValue().equals(CustomFieldEnum.HIGH.getValue())) {
            entity.addField(MyExampleDTO_.customField.getName(), "Custom message about error");
        }
        if (!dto.getCustomFieldAdditional().getValue().equals(CustomFieldEnum.HIGH.getValue())) {
            entity.addField(MyExampleDTO_.customFieldAdditional.getName(), "Custom message about error");
        }
        if (entity.getFields().size() > 0) {
                throw new BusinessException().setEntity(entity);
        }
    }

Step 2 Add сustom method for check to corresponding VersionAwareResponseService.

    @Override
    protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyEntity entity, MyExampleDTO data,
            BusinessComponent bc) {
        validateFields(bc, data);
        return new ActionResultDTO<>(entityToDto(bc, entity));
    }

Sorting

Live Sample · GitHub

Sorting allows you to sort data in ascending or descending order. Sort by key value.

How does it look?

img_sort_list

not applicable

not applicable

How to add?

Example

Enabled by default.

not applicable

not applicable

Required

Live Sample · GitHub

Required allows you to denote, that this field must have a value provided.

How does it look?

img_req_list.png

not applicable

img_req_form.png

How to add?

Example

Add fields.setRequired to corresponding FieldMetaBuilder.

    @Override
    public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, InnerBcDescription bcDescription,
            Long id, Long parentId) {
        fields.setEnumValues(MyExampleDTO_.customField, CustomFieldEnum.values());
        fields.setEnabled(MyExampleDTO_.customField);
        fields.setRequired(MyExampleDTO_.customField);
    }

Works for List.

not applicable

Works for Form.