How to implement Error Display when using Custom Validator

We tried to implement Custom Validator on a LookupPickerField component.
For the validator part, it’s able to display error message accordingly.
However, we are not sure how to gain control of the UI component such that its able to display something like the default “red border” of TextField “required field”.

How should we make the UI component with Custom Validator react and behave consistently as with other default UI?

Thanks.

1 Like

Hi
Did you try it at Entity definition level in the Studio by checking Mandatory?

Mortoza, thank for the input.
The field that we are trying to validate is not based on the “mandatory” field itself. However, the validator is for checking other type of constraints. In this particular case: "When the managedBy field of the Department Entity is changed, we want to check whether the Employee selected as the manager is still assigned to the other department."
And we want to use the same “Red Border” around the field for consistent display language to point out the error LookupPickerField after the validator identified the error.

1 Like

Hi Jeremy, Sorry, I miss-understood what you’re looking for. I think you will have to use CSS programmatically. But I let the CUBA experts guide us. This is interesting to me too.

1 Like

Hi,

You can trigger validation of a Field component using validate() method of the component or validate(fields) method of a Window. Standard fields will reset old state of validation hint, perform validation of a value using added Validators and then change border/background to red with an appropriate error hint.

Example:

<lookupPickerField id="userLookupPicker"
                   required="true"
                   caption="Demo"
                   optionsDatasource="usersDs"/>
<button id="testBtn"
        caption="Test"
        invoke="onTestBtnClick"/>

Trigger validation by click:

public class ExtAppMainWindow extends AppMainWindow {
    @Inject
    private LookupPickerField userLookupPicker;

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);

        userLookupPicker.addValidator(value -> {
            User user = (User) value;

            if ("admin".equals(user.getLogin())) {
                throw new ValidationException("You cannot select admin user");
            }
        });
    }

    public void onTestBtnClick() {
        validate(singletonList(userLookupPicker));
        // or validateAll();
    }
}

Methods of a Window controller automatically show TRAY notification and set focus to the first problem component.

trigger-validation

Error state is automatically reset on value change and if you want to trigger it again on value change - just use ValueChangeListener:

userLookupPicker.addValueChangeListener(e -> {
    validate(singletonList(userLookupPicker));
});
2 Likes

Yuriy,

Thanks a lot. It’s just what we needed.

Hi Yuriy
How did you turn the border red?

Mortoza

It will be red after validate() call if any validator of a field throws ValidationException.

Hi Yuriy
I have following code

nameField.addValidator(value -> {
    if(nameField == null)
        throw new ValidationException("Name fiedltype is empty...");
});

This shows message only, tried this way but it seems not right.

nameField.addValueChangeListener(e -> {
    validateAll();
});

At the moment, validators is not triggered for empty non-required fields. So, you have to mark it as required.

A post was split to a new topic: How to validate readonly fields

Hello, Yuriy!
I have cuba-platform 5.4 and the following code in my controller and xml.
Validation occurs and notification show ok, but there is no red border and tip for the fields.
Fields without custom validator show both the red border and the tip.
Could you advice something?

public void init(Map<String, Object> params) {
        super.init(params);
        startTimeField.addValidator(new Field.Validator() {
            @Override
            public void validate(Object o) throws ValidationException {
                Date startTime = (Date) startTimeField.getValue();
                Date endTime = (Date) endTimeField.getValue();
                if (startTime != null && endTime != null &&
                        (startTime.after(endTime) || startTime.equals(endTime))) {
                    throw new ValidationException("courtbookingslot.editor.time.validation.message");
                }
            }
        });
        
        startTimeField.addListener(new ValueListener() {
            @Override
            public void valueChanged(Object source, String property, @Nullable Object prevValue, @Nullable Object value) {
                validate(Collections.singletonList((Validatable) startTimeField));
            }
        });
    }
<fieldGroup id="fieldGroup" datasource="courtBookingSlotEditorDs" width="100%">
                        <field id="court" required="true" width="500"/>
                        <field id="date" required="true" width="125"/>
                        <field id="startTime" required="true" width="50"/>
                        <field id="endTime"  required="true" width="50"/>
                        <field id="capacity" required="false" width="25"
                               description="msg://courtbookingslot.editor.capacity.description"/>
                        <field id="isAcceptsYouth"
                               description="msg://courtbookingslot.editor.isAcceptsYouth.description"/>
                        <field id="comment" width="500" rows="5"/>
 </fieldGroup>