Error and info messages in a user friendly way

Hi
We have the use case where hundreds of applicants have to fill out dozens of data fields organized in tabs. When he clicks submit or save, all tabs with errors should be marked and all fields containing an error should have an error text. The idea is the following:

image

If the back office person reviews what the applicant entered he might mark the fields which
contains wrong or insufficient information from a business point of view. In such a case he right clicks into the text field and chooses “add comment” and enters the info text. Afterwards the back office informs the applicant to correct the fields. The idea how it could look like is as follows:

image

How could that be implemented in a object oriented way in Cuba, so that we could reuse that in all our interfaces where needed. If we have the feature of putting messages below an entry field we could use the same pattern for errors (validation error) and info messages (business errors).
Any better alternative to the approach above is highly appreciated.

Best
Wern

Hi Werner,

To implement this, you can override ScreenValidation service com.haulmont.cuba.gui.screen.ScreenValidation with your own implementation in CUBA’s web module and set icons to a component container in proper methods. For example, override com.company.tabs.demo.web.ScreenValidation#showValidationErrors with something like this:

    @Override
    public void showValidationErrors(FrameOwner origin, ValidationErrors errors) {
        super.showValidationErrors(origin, errors);
        errors.getAll().forEach(e -> setErrorIcon(e.component));
    }

    private void setErrorIcon(Component component) {
        if (component == null) {
            return;
        }
        if ((component instanceof WebTabWindow) || (component instanceof TabSheet.Tab)) {
            ((Component.HasIcon) component).setIcon("font-icon:EXCLAMATION_CIRCLE");
        } else {
            setErrorIcon(component.getParent());
        }
    }

It’s just a PoC, but I hope you got the idea.

Hi Andrey

Thanks for the Input. This solves one part I am looking for my POC. The more tricky part is the following:

How to show a persistent info message below the Input fields?

  • The info message below the entry filed is a multi line text field which must be persistent for info messages. So should it be a text field in the entity/db model which is connected to that multi line text field in the UI?
  • If I design the form for the end user should I place a invisible multi line text field below the entry field which is shown when required?
  • If so, should I create a custom Text-Entry Fields (based on the standard text entry fields in Cuba) which contains a hidden multi line text field below the entry field which could be displayed or hidden at runtime?

Thanks for a feedback
Wern

I’d have have a look at the appropriate vaadin component, it is supported on Vaadin 7 though, but you can find some inspiration there.

Also, as you suggest, you can implement your own component with an error label and set a proper style to this component to display error or info notification.

Another option use Vaadin’s method com.vaadin.ui.AbstractComponent#setComponentError

I’ll have a look at other options, if a Vaadin can do this, CUBA generic UI should be able to do it too. But remember that you’ll need to take those error labels into account when you plan your screen layout.

hi @werner.schnedl1,

I looked into this topic as well, as it contained some interesting parts and I can remember I had a similar requirement.

What I did was to focus on the question of the comments. I added the following example: GitHub - mariodavid/cuba-example-review-comments

The solution does not require to manually create comments fields with the possibility to forget about them. Instead this solution is generic, that it works for all entities and all attributes.

I will post the README here:


CUBA Petclinic Review Comments

This examples shows how to create review comments for fields on an entity.
The example contains the following business case:

Nurses have to enter a visit documentation after a Pet visit is finished. When they enter the information this documentation has to be reviewed by a Veterinarian. The Vet can take a look at the documentation and add comments to the fields that were entered by the Nurse.

If there is anything to change, the Vet adds a Comment to a Field. Then the nurse can look at the Documentation once again and look at what needs to be changes. The comments are provided via the tooltip on the Field. Additionally the fields are marked with a corresponding (i) icon.

Screenshots

overview

Nurse: Enter Documentation

Vet: Comments Management

Vet: Create Comment

Nurse: Comments Management

How does it work?

The example is built on top ot the following two add-ons:

to store the comments in a generic way.

Storing comments

There is a dedicated entity: EntityAttributeComment which contains the comment information with a link to the VisitDocumentation instance.

@Table(name = "PETCLINIC_ENTITY_ATTRIBUTE_COMMENT")
@Entity(name = "petclinic_EntityAttributeComment")
public class EntityAttributeComment extends EntityAttributeAwareStandardEntity {
    private static final long serialVersionUID = -308675045818098974L;

    @Convert(converter = EntitySoftReferenceConverter.class)
    @MetaProperty(datatype = "EntitySoftReference")
    @Column(name = "REFERS_TO")
    protected com.haulmont.cuba.core.entity.Entity refersTo;

    @Lob
    @Column(name = "COMMENT_")
    protected String comment;


    public com.haulmont.cuba.core.entity.Entity getRefersTo() {
        return refersTo;
    }

    public void setRefersTo(com.haulmont.cuba.core.entity.Entity refersTo) {
        this.refersTo = refersTo;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

}

Comment Indicators in the UI

It is mainly handled in the VisitDocumentationEdit controller class. When the screen is opened, all fields
are traversed in order to find out which fields to mark with a comment:

public class VisitDocumentationEdit extends StandardEditor<VisitDocumentation> {
    
    // ...

    @Subscribe
    protected void onBeforeShow(BeforeShowEvent event) {
        loadComments();

        if (!security.isEntityOpPermitted(EntityAttributeComment.class, EntityOp.UPDATE)) {
            contentTabSheet.removeTab("commentsManagementTab");
        }
    }


    private void loadComments() {
        Collection<EntityAttributeComment> entityAttributeComments =
                softReferenceService.loadEntitiesForSoftReference(EntityAttributeComment.class, getEditedEntity(), "refersTo");
        commentsDc.setItems(entityAttributeComments);
        contentTabSheet.getTabs()
                .forEach(tab -> tab.setIcon(null));
        annotateFormsWithComments();
    }

    private void annotateFormsWithComments() {
        ComponentsHelper.traverseComponents(contentForm, this::markComponentAsCommentedIfRequired);
        ComponentsHelper.traverseComponents(feedbackForm, this::markComponentAsCommentedIfRequired);
    }

    private void markComponentAsCommentedIfRequired(Component component) {
        if (component instanceof Field) {
            Field field = (Field) component;
            MetaProperty metaProperty = metaProperty(field);

            Optional<EntityAttributeComment> possibleComment = commentsDc.getItems()
                    .stream()
                    .filter(entityAttributeComment -> entityAttributeComment.getEntityAttribute().equals(metaProperty))
                    .findAny();

            possibleComment.ifPresent(entityAttributeComment -> {
                        attachCommentToField(field, entityAttributeComment);
                        if (component.getParent().getParent().getParent() instanceof TabSheet) {
                            TabSheet.Tab tab = contentTabSheet.getTab(component.getParent().getParent().getId());
                            tab.setIconFromSet(CubaIcon.INFO_CIRCLE);
                        }
                    }
            );
        }
    }

    private void attachCommentToField(Field componentField, EntityAttributeComment entityAttributeComment) {
        componentField.setDescription(entityAttributeComment.getComment());
        componentField.setIconFromSet(CubaIcon.INFO_CIRCLE);
    }

    private MetaProperty metaProperty(Field field) {
        ContainerValueSource valueSource = (ContainerValueSource) field.getValueSource();
        return valueSource.getMetaPropertyPath().getMetaProperty();
    }
}

Additionally there is a tab for comments management. This Tab is only available for the Role Veterinarian.

4 Likes

Hi Mario
That looks great - I am impressed! I will workout our ideas in to this direction.
Best
Wern

Regarding showing an error or info message below a Text-Field I found this:

Not sure, whether this only works with Vaadin 14.

1 Like