Валидация в экранах

Бин ScreenValidation используется для запуска валидации в экранах. Он имеет следующие методы:

  • validateUiComponents() - используется при коммите изменений в экранах StandardEditor, InputDialog, и MasterDetailScreen. Принимает коллекцию из компонентов или контейнер компонентов и возвращает ошибки валидации в этих компонентах – объект ValidationErrors. Метод validateUiComponents() также может быть использован в произвольном экране. Например:

    @UiController("sample_DemoScreen")
    @UiDescriptor("demo-screen.xml")
    public class DemoScreen extends Screen {
    
        @Autowired
        private ScreenValidation screenValidation;
    
        @Autowired
        private Form demoForm;
    
        @Subscribe("validateBtn")
        public void onValidateBtnClick(Button.ClickEvent event) {
            ValidationErrors errors = screenValidation.validateUiComponents(demoForm);
            if (!errors.isEmpty()) {
                screenValidation.showValidationErrors(this, errors);
                return;
            }
        }
    }
  • showValidationErrors() - показывает уведомление со всеми ошибками и проблемными компонентами. Метод принимает экран и объект ValidationErrors. Также используется по умолчанию в экранах StandardEditor, InputDialog, и MasterDetailScreen.

  • validateCrossFieldRules() - accepts a screen and an entity and returns the ValidationErrors object. By default, it is used in the StandardEditor, MasterDetailScreen, and in the editor of the DataGrid. Выполняет правила перекрестной проверки, установленные на поля сущности.

    Editor screens validate class-level constraints on the commit if the constraints include the UiCrossFieldChecks group and all attribute-level constraint checks are successful. You can disable this type of validation using the setCrossFieldValidate() method of the controller. The validateCrossFieldRules() method also can be used in an arbitrary screen.

    В качестве примера рассмотрим сущность Event, для которой можно определить аннотацию уровня класса @EventDate, для проверки того, что дата Start date должна быть раньше даты End date.

    @JmixEntity
    @Table(name = "SAMPLE_EVENT")
    @Entity(name = "sample_Event")
    @EventDate(groups = {Default.class, UiCrossFieldChecks.class})
    public class Event {
        @JmixGeneratedValue
        @Column(name = "ID", nullable = false)
        @Id
        private UUID id;
    
        @Column(name = "NAME")
        @InstanceName
        private String name;
    
        @Column(name = "START_DATE")
        @Temporal(TemporalType.TIMESTAMP)
        private Date startDate;
    
        @Column(name = "END_DATE")
        @Temporal(TemporalType.TIMESTAMP)
        private Date endDate;
    
        // ...

    Определение аннотации выглядит следующим образом:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = EventDateValidator.class)
    public @interface EventDate {
    
        String message() default "Start date must be earlier than the end date";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }

    Вот класс EventDateValidator:

    public class EventDateValidator implements ConstraintValidator<EventDate, Event> {
    
        @Override
        public boolean isValid(Event event, ConstraintValidatorContext context) {
            if (event == null) {
                return false;
            }
    
            if (event.getStartDate() == null || event.getEndDate() == null) {
                return false;
            }
    
            return event.getStartDate().before(event.getEndDate());
        }
    }

    Теперь можно использовать метод validateCrossFieldRules() в произвольном экране.

    @UiController("sample_DemoScreen")
    @UiDescriptor("demo-screen.xml")
    public class DemoScreen extends Screen {
    
        @Autowired
        private ScreenValidation screenValidation;
    
        @Autowired
        protected Metadata metadata;
    
        @Autowired
        protected TimeSource timeSource;
    
        @Subscribe("validateDateBtn")
        public void onValidateDateBtnClick(Button.ClickEvent event) {
            Event demoEvent = metadata.create(Event.class);
            demoEvent.setName("Demo event");
            demoEvent.setStartDate(timeSource.currentTimestamp());
            demoEvent.setEndDate(DateUtils.addDays(demoEvent.getStartDate(), -1));
            ValidationErrors errors = screenValidation.validateCrossFieldRules(this, demoEvent);
            if (!errors.isEmpty()) {
                screenValidation.showValidationErrors(this, errors);
            }
        }
    }
  • Методы showUnsavedChangesDialog() и showSaveConfirmationDialog() показывают диалоги с предупреждением о несохраненных изменениях либо с кнопками Yes и No, либо Save, Do not save, и Cancel. Используются в методе StandardEditor preventUnsavedChanges(). Выбрать тип диалога можно с помощью свойства приложения jmix.ui.screen.use-save-confirmation.