1

In JSF 2.X, can I render a component only when the validation success?

In my application I have many fields that must be filled. These data can be imported from a WebService through a search key.

When the user enter a valid search key the system searches the other fields and render them with the new values. But when the user enter a nonexistent key (or any other validation error) the server generates a validation error but still renders the fields, thus losing any data that there were filled.

What I need is that the user can perform the query and that if the query does not return results, this does not affect any data that he has already entered.

Below is a code example. Thus, if the user has filled in the fields inside updateThisOnSuccess and just after making an attempt to query without success, the value that is filled in is not lost.

    <h:inputText value="#{controller.searchWebService}" >
        <f:ajax execute="@this" render="updateThisOnSuccess messages" />
    </h:inputText>

    <h:panelGroup id="updateThisOnSuccess">
        <h:inputText value="#{controller.field}" />
        <!-- other fields -->
    </h:panelGroup>

Submit the field values to run the search also does not seem an option as this will cause need to validate the fields inside updateThisOnSuccess.


Note: I saw the answer given by @BalusC to a similar question, but this is different from what I'm wondering why, in that case, foo-holder is always rendered and foo is conditioning. It's not my case, since this approach would make the controls do not appear when the validation fails.

Community
  • 1
  • 1
Marcelo Barros
  • 930
  • 9
  • 16
  • Your question is quite long winded, but I gather that you basically want `rendered="#{not empty controller.searchWebService}"`? After all, it's just a matter of specifying exactly the desired condition in the `rendered` attribute. – BalusC Sep 08 '15 at 06:54
  • Excuse me for writing. I tried but English isn't my native language. What I need is not that. I need that the values entered in the input[text], select, etc., within the _panelGroup_ _updateThisOnSuccess_ be maintained if the validation fails on _controller.searchWebService._ If the validation pass they have to be rerendered with the new values. In other words, it would be as if Ajax were that: Validation OK `` Validation Failed `` – Marcelo Barros Sep 08 '15 at 17:48

4 Answers4

2

Try this

<h:panelGroup id="updateThisOnSuccess">
    <ui:fragment rendered="#{not facesContext.validationFailed}">
        <h:inputText value="#{controller.field}" />
        <!-- other fields -->
    </ui:fragment>
</h:panelGroup>
A.Panzer
  • 391
  • 3
  • 15
0

You can change the components that will be processed in render phase changing the Collection at getRenderIds() of PartialViewContext. According to documentation this Collection is mutable.

FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().remove("formName:updateThisOnSuccess");

To test this solution, I used this controller:

@Named
@ViewScoped
public class Controller implements Serializable {

    private static final long serialVersionUID = 1L;

    private final static List<String> LIST_VALID_WEB_SERVICE_SEARCHS =
        Arrays.asList(new String[] {"foo", "bar"});

    private String webServiceParameter;
    private Integer field01;

    public void searchWebService() {

        if (LIST_VALID_WEB_SERVICE_SEARCHS.contains(getWebServiceParameter())) {
            setField01(123);
        } else {

            FacesContext facesContext = FacesContext.getCurrentInstance();

            facesContext.getPartialViewContext().getRenderIds().remove("formFields");

            FacesMessage facesMessage = new FacesMessage("Search not found in WebService.");
            facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
            facesContext.addMessage("formName:searchWebService", facesMessage);
        }
    }

    public void submit() {
        System.out.println("submitted");
    }

    // Getters and Setters
}

And used this view:

<h:form id="formSearch">
    <h:inputText id="webServiceParameter" value="#{controller.webServiceParameter}">
        <f:ajax execute="@this" render="formFields messages" listener="#{controller.searchWebService}" />
    </h:inputText><br />
</h:form>

<h:form id="formFields">
    <h:inputText id="field01" value="#{controller.field01}" required="true">
        <f:validateLongRange minimum="2" maximum="345" />
    </h:inputText><br />
    <!-- other fields -->

    <h:commandButton value="submit" action="#{controller.submit}">
        <f:ajax render="@form messages" execute="@form" />
    </h:commandButton>
</h:form>

<h:messages id="messages" />
Marcelo Barros
  • 930
  • 9
  • 16
  • Could you write aditional code simulating model update when the WS success? Did you look at my solution? – Javier Haro Sep 09 '15 at 08:20
  • @lametaweb I have edited my answer to satisfying your comment. – Marcelo Barros Sep 09 '15 at 15:44
  • Ok. I think it is a very good solution. @BalusC you said this problem is quite long winded. Do you think this solution is a duplicated answer or on the contrary put anything new in the escene? – Javier Haro Sep 09 '15 at 17:36
0

Plaase try this. The requirements are that you must implement model validations with Bean Validation and the search field must implement JSF validation if required. If you write "123456" then data is returned, else nothing is returned and a message is printed.

The backing bean:

@Named
@ViewScoped
public class yourBean implements Serializable{

    private static final long serialVersionUID = 1L;

    @Size(min=2)
    private String field01;

    private String searchWebService;    

    public void saveF(){
        System.out.println("save");
    }

    public void searchWebServiceF(){

        Boolean successWS = ("123456").equals(this.searchWebService);
        if(successWS){
            this.setField01("WS data");
        }else{
            FacesContext.getCurrentInstance().
                addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "WS fails", ""));
        }
    }

    public String getSearchWebService() {
        return searchWebService;
    }
    public void setSearchWebService(String searchWebService) {
        this.searchWebService = searchWebService;
    }
    public String getField01() {
        return field01;
    }
    public void setField01(String field01) {
        this.field01 = field01;
    }
}

In your page:

<h:form id="form01">
<h:messages id="message"/>
    <h:inputText id="wsid" value="#{pruebasBorradorBean.searchWebService}">
        <f:validateLength maximum="6"/>
        <f:ajax execute="@form" render="@form" listener="#{pruebasBorradorBean.searchWebServiceF()}" />
    </h:inputText>

    <h:panelGroup id="thedata">
        <h:inputText value="#{pruebasBorradorBean.field01}">
            <f:validateBean disabled="#{param['javax.faces.source']!='form01:save'}"/>
        </h:inputText>
        <!-- other fields -->
    </h:panelGroup>
    <h:commandButton id="save" value="submit">
        <f:ajax render="thedata message" execute="@this thedata" listener="#{pruebasBorradorBean.saveF()}"/>
    </h:commandButton>

</h:form>
Javier Haro
  • 1,255
  • 9
  • 14
  • Great! In my example your code works well, as requirements. But in my real application the _other fields_ has many _Converters_, such as _Integer_ and _Date_. Can you explain how can I do if the _field01_ is an _Integer_ in _PruebasBorradorBean_? If the user put invalid characters can I "disable the _Converter_" like you disable the _Validator_? In my tests, this last test case does not work, because if the user tries to search the WebService with invalid characters in _field01_ it will accuse the conversion error. – Marcelo Barros Sep 09 '15 at 14:29
-1

You can do something like that:

<f:ajax execute="@this" render="#{controller.success} message"/>

where success is a String attribute that will be empty if the WS fails and will be "updateThisOnSuccess" if not .

Or you could get rid of the JSF validation mechanism for informing the user the WS has failed. Think of it, it is not really a validation of the Model. You could draw an icon beside the WS Id field in red color or something similar using a boolean flag attribute in the backing bean.

Javier Haro
  • 1,255
  • 9
  • 14
  • Please test code before doing off as answer. If you can't tell from top of head if given code works, better post a "try this" comment. – BalusC Sep 08 '15 at 08:06