Как предотвратить запуск следующей кнопки "Мастер", чтобы активировать проверку клиента?

У меня в приложении JSF 2.2 + PrimeFaces есть мастер с тремя вкладками. На каждой вкладке у меня есть форма для захвата данных от пользователя. Каждая из этих форм имеет некоторые валидации. Прямо сейчас, когда я нажимаю дальше, чтобы перейти к следующей вкладке, он проверяет данные из формы. Я не хочу, чтобы это произошло.

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

Я смог исправить это, НЕ проверив проверку на стороне клиента (т.е. не используя слово требуемое в полях ввода) и проверяя только на бэкэнд. Проблема в том, что я хочу проверку на стороне клиента.

Мой мастер выглядит так:

<h:form id="wizard">

    <p:wizard flowListener="#{afiliadoController.onFlowProcess}" nextLabel="Siguiente" 
    backLabel="Anterior" showStepStatus="true">

    <p:tab id="afiliadoTab" title="Afiliado">

            <p:growl autoUpdate="true"/>

            <p:panel styleClass="panels" id="panelAfiliado" style="margin-bottom:1em;" >

                <p:focus context="panelAfiliado"/>

                <h1> Agregue un Afiliado </h1>

                <h:panelGrid columns="4" styleClass="panelGrid" >

                    <p:outputLabel for="nombres" value="Nombres:" />

                    <p:inputText id="nombres" value="#{afiliadoController.afiliado.nombre}"
                    requiredMessage="Debe insertar un nombre." />

                    <p:outputLabel for="apellidos" value="Apellidos:" />

                    <p:inputText id="apellidos" value="#{afiliadoController.afiliado.apellido}"
                    requiredMessage="Debe insertar un apellido." />

                    <p:outputLabel for="estadoCivil" value="Estado Civil:" />

                    <p:selectOneMenu id="estadoCivil" effect="drop" value="#{afiliadoController.afiliado.estado_civil}" 
                    requiredMessage="Debe seleccionar un estado civil." >

                        <f:selectItem itemLabel="Estado Civil" itemValue=""/>
                        <f:selectItem itemLabel="Soltero" itemValue="S"/>
                        <f:selectItem itemLabel="Casado" itemValue="C"/>
                        <f:selectItem itemLabel="Union Libre" itemValue="U"/>
                        <f:selectItem itemLabel="Divorciado" itemValue="D"/>
                        <f:selectItem itemLabel="Viudo" itemValue="V"/>

                    </p:selectOneMenu>

                    <p:outputLabel for="direccion" value="Direccion:" />

                    <p:inputText id="direccion" value="#{afiliadoController.afiliado.direccion}"/>

                    <p:outputLabel for="telefono" value="Telefono:" />

                    <p:inputMask id="telefono" value="#{afiliadoController.afiliado.telefono}" mask="(999) 999-9999" 
                    requiredMessage="Debe insertar un telefono." />

                    <p:outputLabel for="fechaNacimiento" value="Fecha de Nacimiento:"/>

                    <p:calendar id="fechaNacimiento" yearRange="c-100:c" pattern="dd/MM/yyyy" navigator="true" 
                    value="#{afiliadoController.afiliado.fecha_nacimiento}" 
                    requiredMessage="Debe insertar su fecha de nacimiento." showOn="button" 
                    readonly="#{facesContext.currentPhaseId.ordinal eq 6}">

                        <p:ajax event="dateSelect" listener="#{afiliadoController.dateSelect}" update="edadAfi"/>

                    </p:calendar>

                    <p:outputLabel for="plan" value="Plan:" />                  
                    <p:selectOneMenu id="plan" effect="drop" value="#{afiliadoController.afiliado.plan}" 
                    requiredMessage="Debe seleccionar un plan." >

                        <f:selectItem itemLabel="Seleccione un plan" itemValue=""/>
                        <f:selectItem itemLabel="Vital Base" itemValue="1"/>
                        <f:selectItem itemLabel="Vital Elite" itemValue="2"/>
                        <f:selectItem itemLabel="Plan Vital Elite Internacional" itemValue="3"/>

                    </p:selectOneMenu>

                    <h:outputText value="Fecha: #{of:formatDate(now, 'dd/MM/yyyy')}"/>

                    <h:outputText value="Edad Afiliado: #{afiliadoController.afiliado.edad}" id="edadAfi"/>

                    <p:outputLabel for="modalidad" value="Modalidad:" />                    
                    <p:selectOneMenu id="modalidad" effect="drop" value="#{afiliadoController.afiliado.modalidad}" 
                    requiredMessage="Debe seleccionar una modalidad." required="true">

                        <f:selectItem itemLabel="Seleccione una modalidad" itemValue=""/>
                        <f:selectItem itemLabel="Solo Titular Del Contrato" itemValue="A"/>
                        <f:selectItem itemLabel="Titular del Contrato + Grupo Familiar" itemValue="B"/>

                        <f:validateBean disabled="#{!request.getParameter('validate')}" />

                    </p:selectOneMenu>

                    <p:commandButton value="Insertar" icon="fa fa-save" process="panelAfiliado" update="afiliadoTable"
                     actionListener="#{afiliadoController.insertAfiliado}" >

                        <f:param name="validate" value="true"/>

                     </p:commandButton>

                </h:panelGrid>         

            </p:panel>

    </p:tab>

    </p:wizard>

</h:form>

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

Я делаю это, потому что я хочу, чтобы ключевое слово вводить работало отдельно для каждой формы. С идентификатором id afiliadoTab есть некоторые проверки. Я хочу, чтобы эти проверки выполнялись только при нажатии кнопки:

<p:commandButton value="Insertar" icon="fa fa-save" process="panelAfiliado" update=":wizard:tablaAfiliados:afiliadoTable"
                         actionListener="#{afiliadoController.insertAfiliado}" validateClient="true"/>

Я не хочу, чтобы эти проверки выполнялись, когда я нажимаю NEXT. Что я могу сделать? (Я знаю, что в SO есть несколько подобных вопросов, но я не мог получить ответ. Например, один из них использует пользовательские виджеты-виджеты. Я пытался это сделать, но нашел несколько проблем:

  • Как я могу отобразить кнопку "Назад" только при необходимости? (Не отображать его на первой вкладке)

  • Проверки все еще существуют, даже когда я использую @this.

Каковы мои лучшие варианты?

Необходимый мастер проверки подлинности

Ответ 1

Я, наконец, понял способ сделать это благодаря @Geinmachi и @BaulusC post здесь

Итак, это обновленный код:

<p:panel styleClass="panels" id="panelAfiliado" style="margin-bottom:1em;" >

<p:focus context="panelAfiliado"/>

<h1> Agregue un Afiliado </h1>

<h:panelGrid columns="4" styleClass="panelGrid" >

  <p:outputLabel for="nombres" value="Nombres:" />

  <p:inputText id="nombres" value="#{afiliadoController.afiliado.nombre}"
  requiredMessage="Debe insertar un nombre." required="#{request.getParameter('validate')}"/>

  <p:outputLabel for="apellidos" value="Apellidos:" />

  <p:inputText id="apellidos" value="#{afiliadoController.afiliado.apellido}"
  requiredMessage="Debe insertar un apellido." required="#{request.getParameter('validate')}"/>

  <p:outputLabel for="estadoCivil" value="Estado Civil:" />

  <p:selectOneMenu id="estadoCivil" effect="drop" value="#{afiliadoController.afiliado.estado_civil}" 
  requiredMessage="Debe seleccionar un estado civil." required="#{request.getParameter('validate')}">

    <f:selectItem itemLabel="Estado Civil" itemValue=""/>
    <f:selectItem itemLabel="Soltero" itemValue="S"/>
    <f:selectItem itemLabel="Casado" itemValue="C"/>
    <f:selectItem itemLabel="Union Libre" itemValue="U"/>
    <f:selectItem itemLabel="Divorciado" itemValue="D"/>
    <f:selectItem itemLabel="Viudo" itemValue="V"/>

  </p:selectOneMenu>

  <p:outputLabel for="direccion" value="Direccion:" />

  <p:inputText id="direccion" value="#{afiliadoController.afiliado.direccion}" required="#{request.getParameter('validate')}"/>

  <p:outputLabel for="telefono" value="Telefono:" />

  <p:inputMask id="telefono" value="#{afiliadoController.afiliado.telefono}" mask="(999) 999-9999" 
  requiredMessage="Debe insertar un telefono." required="#{request.getParameter('validate')}"/>

  <p:outputLabel for="fechaNacimiento" value="Fecha de Nacimiento:"/>

  <p:calendar id="fechaNacimiento" yearRange="c-100:c" pattern="dd/MM/yyyy" navigator="true" 
  value="#{afiliadoController.afiliado.fecha_nacimiento}" 
  requiredMessage="Debe insertar su fecha de nacimiento." showOn="button" 
  readonly="#{facesContext.currentPhaseId.ordinal eq 6}" required="#{request.getParameter('validate')}">

    <p:ajax event="dateSelect" listener="#{afiliadoController.dateSelect}" update="edadAfi"/>

  </p:calendar>

  <p:outputLabel for="plan" value="Plan:" />              
  <p:selectOneMenu id="plan" effect="drop" value="#{afiliadoController.afiliado.plan}" 
  requiredMessage="Debe seleccionar un plan." required="#{request.getParameter('validate')}">

    <f:selectItem itemLabel="Seleccione un plan" itemValue=""/>
    <f:selectItem itemLabel="Vital Base" itemValue="1"/>
    <f:selectItem itemLabel="Vital Elite" itemValue="2"/>
    <f:selectItem itemLabel="Plan Vital Elite Internacional" itemValue="3"/>

  </p:selectOneMenu>

  <h:outputText value="Fecha: #{of:formatDate(now, 'dd/MM/yyyy')}"/>

  <h:outputText value="Edad Afiliado: #{afiliadoController.afiliado.edad}" id="edadAfi"/>

  <p:outputLabel for="modalidad" value="Modalidad:" />              
  <p:selectOneMenu id="modalidad" effect="drop" value="#{afiliadoController.afiliado.modalidad}" 
  requiredMessage="Debe seleccionar una modalidad." required="#{request.getParameter('validate')}">

    <f:selectItem itemLabel="Seleccione una modalidad" itemValue=""/>
    <f:selectItem itemLabel="Solo Titular Del Contrato" itemValue="A"/>
    <f:selectItem itemLabel="Titular del Contrato + Grupo Familiar" itemValue="B"/>

    <!-- <f:validateBean disabled="#{!request.getParameter('validate')}" /> -->

  </p:selectOneMenu>

  <p:commandButton value="Insertar" icon="fa fa-save" process="panelAfiliado" update="afiliadoTable"
   actionListener="#{afiliadoController.insertAfiliado}" >

    <f:param name="validate" value="true"/>

   </p:commandButton>

</h:panelGrid>       

Взгляните на все мои поля. У всех это есть:

required="#{request.getParameter('validate')}"

Если вы посмотрите на мою кнопку, она имеет:

<f:param name="validate" value="true"/>

Таким образом, когда я нажимаю кнопку NEXT на моем мастере, он НЕ активирует проверки. Проверки будут ТОЛЬКО активироваться, когда я нажимаю кнопку в этой конкретной форме!

Я надеюсь, что кому-нибудь это поможет.

Ответ 2

У вас есть вложенные формы. Каждый <h:form> на вкладке находится внутри другого <h:form> снаружи <p:wizard>. Вам не нужны отдельные формы, только один внешний мастер.

EDIT:

Для этого существует некоторое обходное решение, которое работает для меня (не проверяйте поле после нажатия NEXT, но проверяете после нажатия на кнопку для подтверждения).

Для полей, которые вы не хотите проверять в NEXT, добавьте этот тег (например, для <h:inputText>)

<f:validateBean disabled="#{!request.getParameter('validate')}" /> и к вашей кнопке добавьте этот тег <f:param name="validate" value="true"/>.

Ответ 3

Итак, если у кого-то будет проблема проверки, аналогичная этому, есть два случая:

  • Если вы используете проверку JSF как атрибут PrimeFaces required или обычные теги типа <f:validateRequired/>, вы можете сделать required = "#{!request.getParameter('validate')}" и <f:validateRequired disabled="#{!request.getParameter('validate')}"/> как OP или
  • Если вы используете проверку JSR Bean, например @NotNull, вы можете сделать <f:validateBean disabled="#{!request.getParameter('validate')}" />

чтобы отключить проверку с помощью <f:param name="validate" value="true"/> клавише действия.