entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Buenas estoy realizando una aplicación web en JSF 2.2 utilizando Primefaces 5, en concreto estoy tratando de realizar un datatable donde el atributo required de un input debe ser true si la linea del datatable que lo contiene esta seleccionada, de momento lo he implementado de la siguiente forma:

<p:dataTable value="#{ventaController.venta.lineas}" id="data"
    var="linea" selection="#{ventaController.albaran.lineas}"
    rowKey="#{linea.id}">

    <p:ajax event="rowSelectCheckbox" update="data" >
    <p:ajax event="rowUnselectCheckbox" update="data" >
    <p:ajax event="rowSelect" update="data" >
    <p:ajax event="rowUnselect" update="data" >
    <p:ajax event="toggleSelect" update="data" >

    <p:column selectionMode="multiple" width="16" >
    <p:column id="cantidadPen" headerText="C. pendiente">
        <h:outputText style=" text-align:right;"
            value="#{linea.cantidadPendiente}" >

    </p:column>
    <p:column id="cantidadEntr" headerText="Entregar">

        <pe:inputNumber id="cantidadEntr"
            required="#{ventaController.albaran.lineas.contains(linea)}"
            value="#{linea.cantidadAEntregar}"
            decimalSeparator="." thousandSeparator=","
            maxValue="#{linea.cantidadPendiente}" >

    </p:column>
</datatable>

Casi funciona pero tiene un bug que voy a tratar de explicar lo mejor posible.

Partimos de que una linea esta seleccionada y su input vacío, al estar seleccionada ese input tiene el atributo required=true, al deseleccionarla se dispara el siguiente evento:

<p:ajax event="rowUnselect" update="data" >

el cual actualiza el datatable, en este punto el atributo required del input debería cambiar a false al encontrarse la linea deseleccionada, de esto se encarga la siguiente expresion:

 required="#{ventaController.albaran.lineas.contains(linea)}"

el problema es que al actualizar el datatable esta ocurriendo la validación del input tomando como true el valor del atributo required, es decir al actualizar esa seccion del DOM se esta realizando la validacion con el valor anterior, que era true, por lo que la validación falla y no permite enviar el formulario mientras que el input no sea rellenado.

No se si me he explicado muy bien, espero que se me haya entendido, si no se entiende comentarlo e intentaré aclararlo.

También añadir que la siguiente linea no me convence mucho ya que es una llamada al servidor con un coste computacional bastante elevado para algo tan sencillo como lo que busco, pero no se me ocurre otra forma mas simple de hacerlo, si a alguien se le ocurre una manera mas sencilla de hacerlo se lo agradecería mucho.

 required="#{ventaController.albaran.lineas.contains(linea)}"

Un saludo

1 Respuesta

3votos

Javi2EE Puntos6630

Para quien pueda interesarle, no hay una forma de poder realizar esto con la validación normal de JSF, ya que el evento de selección y deseleccion necesita como mínimo process=@this, el cual procesa la linea completa del datatable dando lugar a la validación de cualquier input en la misma, el único process que podría funcionar seria @none pero este detiene el evento de la selección, así que al final tuve que hacerlo de otra manera, lo comparto sin entrar en muchos detalles:

Añadir el parametro global para activar la validacion en el cliente:

<context-param>
  <param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name>
    <param-value>true</param-value>
  </context-param>

Declaramos un bean validator que redirecciona al validator javascript

package com.gestion.controller;

import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

import org.primefaces.validate.ClientValidator;

@FacesValidator("custom.CantidadEntregaValidator")

public class CantidadEntregaValidator implements Validator, ClientValidator {
    public CantidadEntregaValidator(){
    }

    @Override
    public Map<String, Object> getMetadata() {
       return null;  // No metadata required on client side
    }

    @Override
    public String getValidatorId() {
        return "custom.CantidadEntregaValidator";
    }

    @Override
    public void validate(FacesContext someFacesContext, UIComponent someUIComponent, Object o) throws ValidatorException {

    }
}

Declarar el validator mediante javascript:

<script language="javascript" type="text/javascript">

    PrimeFaces.validator['custom.CantidadEntregaValidator'] = {

            throwError: function(detail) {
                throw {
                    summary: 'Validation Error',
                    detail: detail
                }
            },

            validate: function (element, value) {
                var tr = element.closest('tr');
                var input = tr.find("input:checkbox");
                if(input.is(':checked')){//comprobamos si la linea esta seleccionada
                    if(value==null ){
                        this.throwError("Error");}
                }
            }
        };
</script>

Utilizo inputText en lugar de inputNumber, añadirle atributo validator

<p:inputText id="cant_input" validator="custom.CantidadEntregaValidator" value="#{linea.cantidadAEntregar}"/>

Por ultimo en el botón que se encargue de enviar el formulario añadir el atributo validate client

<p:commandButton value="Guardar" actionListener="#{ventaController.create}"  validateClient="true" />

Así de sencillo ;)
Como consejo personal, si JSF se cruza en vuestro camino huid mientras podáis.
Un saludo

0voto

Peter comentado

Gracias por compartir la respuesta!

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta