Визуализация компонента только после успешной проверки

В JSF 2.X могу ли я визуализировать компонент только после успешной проверки?

В моем приложении у меня есть много полей, которые необходимо заполнить. Эти данные можно импортировать из веб-сервиса с помощью ключа поиска.

Когда пользователь вводит действительный ключ поиска, система выполняет поиск в других полях и отображает их с новыми значениями. Но когда пользователь вводит несуществующий ключ (или любую другую ошибку проверки), сервер генерирует ошибку проверки, но все же отображает поля, теряя при этом все данные, которые там были заполнены.

Что мне нужно, так это то, что пользователь может выполнить запрос и что, если запрос не возвращает результатов, это не влияет на данные, которые он уже ввел.

Ниже приведен пример кода. Таким образом, если пользователь заполнил поля внутри updateThisOnSuccess и сразу после неудачной попытки запроса, заполненное значение не теряется.

    <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>

Отправка значений полей для запуска поиска также не представляется возможным, так как это вызовет необходимость проверки полей внутри updateThisOnSuccess.


Примечание. Я видел ответ, данный @BalusC на аналогичный вопрос, но это отличается от того, что мне интересно, почему , в этом случае foo-holder всегда отображается, а foo является обусловливающим. Это не мой случай, так как при таком подходе элементы управления не будут отображаться при сбое проверки.


person Marcelo Barros    schedule 08.09.2015    source источник
comment
Ваш вопрос довольно многословен, но я понимаю, что вы в основном хотите rendered="#{not empty controller.searchWebService}"? В конце концов, это всего лишь вопрос точного указания желаемого условия в атрибуте rendered.   -  person BalusC    schedule 08.09.2015
comment
Извините, что пишу. Я пытался, но английский не мой родной язык. Мне нужно не это. Мне нужно, чтобы значения, введенные в input[text], select и т. д. в пределах panelGroup updateThisOnSuccess, сохранялись, если проверка не удалась на controller.searchWebService. Если проверка прошла успешно, они должны быть перерисованы с новыми значениями. Другими словами, это было бы так, как если бы Ajax был следующим: Проверка прошла успешно <f:ajax execute="@this" render="updateThisOnSuccess messages" /> Проверка не удалась <f:ajax execute="@this" render="messages" />   -  person Marcelo Barros    schedule 08.09.2015


Ответы (4)


Попробуй это

<h:panelGroup id="updateThisOnSuccess">
    <ui:fragment rendered="#{not facesContext.validationFailed}">
        <h:inputText value="#{controller.field}" />
        <!-- other fields -->
    </ui:fragment>
</h:panelGroup>
person A.Panzer    schedule 11.09.2015

Пожалуйста, попробуйте это. Требования заключаются в том, что вы должны реализовать проверку модели с помощью Bean Validation, а поле поиска должно реализовать проверку JSF, если это необходимо. Если вы пишете «123456», то возвращаются данные, иначе ничего не возвращается и печатается сообщение.

Поддерживающий компонент:

@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;
    }
}

На вашей странице:

<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>
person Javier Haro    schedule 08.09.2015
comment
Большой! В моем примере ваш код работает хорошо, как и требования. Но в моем реальном приложении другие поля имеют много преобразователей, таких как Integer и Date. Можете ли вы объяснить, что мне делать, если field01 является Integer в PruebasBorradorBean? Если пользователь ввел недопустимые символы, могу ли я отключить преобразователь так же, как вы отключили валидатор? В моих тестах этот последний тестовый пример не работает, потому что, если пользователь попытается выполнить поиск WebService с недопустимыми символами в field01, он обвинит ошибку преобразования. - person Marcelo Barros; 09.09.2015

Вы можете изменить компоненты, которые будут обрабатываться на этапе рендеринга, изменив коллекцию по адресу getRenderIds() из PartialViewContext. Согласно для документации эта коллекция является изменяемой.

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

Чтобы протестировать это решение, я использовал этот контроллер:

@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
}

И использовал это представление:

<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" />
person Marcelo Barros    schedule 08.09.2015
comment
Не могли бы вы написать дополнительный код, имитирующий обновление модели при успешном выполнении WS? Ты смотрел мое решение? - person Javier Haro; 09.09.2015
comment
@lametaweb Я отредактировал свой ответ, чтобы удовлетворить ваш комментарий. - person Marcelo Barros; 09.09.2015
comment
В порядке. Я думаю, что это очень хорошее решение. @BalusC, ты сказал, что эта проблема довольно запутанная. Как вы думаете, это решение является дублированным ответом или, наоборот, добавляет что-то новое в сцену? - person Javier Haro; 09.09.2015

Вы можете сделать что-то вроде этого:

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

где success — это строковый атрибут, который будет пустым, если WS выйдет из строя, и будет «updateThisOnSuccess», если нет.

Или вы можете избавиться от механизма проверки JSF для информирования пользователя о сбое WS. Подумайте об этом, на самом деле это не проверка Модели. Вы можете нарисовать значок рядом с полем WS Id красным цветом или что-то подобное, используя атрибут логического флага в компоненте поддержки.

person Javier Haro    schedule 08.09.2015
comment
Пожалуйста, проверьте код, прежде чем делать ответ. Если вы не можете сразу сказать, работает ли данный код, лучше опубликуйте этот комментарий. - person BalusC; 08.09.2015