简体   繁体   中英

How to handle global errors in forms in Play Framework 2 (Java)

When handling errors in forms in Play Framework 2 (Java), I want to present an overall error message that warns the user that something went wrong, eg " Form X not updated ". One way to do this is, in addition to the errors for each form field, to create a global error, and then present this on each template:

Controller:

if(form.hasErrors()) {
    form.reject("Form X not updated."); // This creates a global error
}

Template:

@if(form.hasGlobalErrors) {
    @someFunctionToPresentErrors(from.globalError.message))
}

However, adding this identical piece of code to each template that contains a form violates the DRY principle.

My best solution so far is to add the error message to Http.Context instead and then intercepting the error message in the main template that is called by each template:

Controller:

Http.Context.current().args.put("error", "Form X not updated.");

Main template:

@if(Http.Context.current().args.containsKey("error")){
    @someFunctionToPresentErrors(
        Http.Context.current().args.get("error").asInstanceOf[String])
}

This is better because it allows me to keep the error presentation stuff in one place, but it feels like abuse of Http.Context . Note that flash(...) can also be used to pass variables implicitly around and gives the same effect as Http.Context , but that this is not allowed when calling badRequest(...) , since flash should only be used for redirects. In any case, I am thinking there should be a better way to do this using the form machinery provided by Play Framework.

Is there a best practice for this?

I think you overvalue the DRY violation in this case - actually I realized that even global error isn't so global - actually every form has it's own context. Anyway to make work faster you can make usage from template tags and Flash scope

First add two generic public methods ie in your Application controller

public static void flashGlobalError() {
    flashGlobalError("Oppps... error occurred and I don't know the reason ;(");
}

public static void flashGlobalError(String msg) {
    flash("globalError", msg);
}

then create a parameterless tag template ie views/tags/globalErrorByFlash.scala.html

@if(flash.get("globalError")) {
    <div style="background: red">
        <h4>Error!</h4>
        @flash.get("globalError")
    </div>
}

and include it in your main template (or within selected views only) as:

<body>
    @tags.globalErrorByFlash()
    @content
</body>

So every time when you want to display this error you can just do it in your action:

if(form.hasErrors()) {
    Application.flashGlobalError();
    return badRequest(...);
}

or

if(form.hasErrors()) {
    Application.flashGlobalError("This case is quite bit different...");
    return badRequest(...);
}

The best benefit from this approach is that you don't need to depend on Form.form(T) as you can use it anywhere:

if (1 != 0){
    Application.flashGlobalError("Stupido! One isn't equal to Zero!");
}

Finally : keep in mind that any value kept in flash scope lives just for one request, so it may disappear after redirect. View/template rendering is also counted, so if you'll redirect the error to new action, forward it in the controller, so redirected view can see it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM