Enviar respuesta 
 
Calificación:
  • 1 votos - 5 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Sobre el ConditionalValidator
armando Sin conexión
Developer
*

Mensajes: 8
Registro en: Apr 2012
Reputación: 0
Mensaje: #1
Sobre el ConditionalValidator
Buenas noches profesor, ya logramos probar y correr el conditionalValidator, tal como lo escribió en la wiki, que aclaró mucho las dudas sobre el funcionamiento del conditionalValidator. La cuestión es sobre su funcionalidad, la duda del por que no se muestra ningún error si los basevalidators, A y B, detectan errores?, dependiendo del tipo de validación por supuesto. La cuestión es que en caso tal, de que los basevalidators detecten errores, no se mostrara ningún mensaje al usuario al momento de validar un campo, todos los mensajes de error se delegan a los subvalidadores. Entonces si hay algún error en realidad a nivel de los basevalidators el usuario no se va a enterar de nada?

La pregunta y la propuesta, en este caso, es dejar la implementación del ConditionalValidator tal cual como esta, que ya esta probado que funciona, encadenando validadores y todo. Pero Mi propuesta es quitar esos basevalidators del constructor de la clase, y esos mismos baseValidators convertirlos en los propios subvalidadores efectivos. De manera que efectivamente se construya un validador condicional que muestre todo los mensajes de error dependiendo de la condición elegida.
(Este mensaje fue modificado por última vez en: 11-07-2012 11:09 AM por armando.)
11-07-2012 11:04 AM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
demian Sin conexión
Administrator
*******

Mensajes: 1.808
Registro en: Jun 2010
Reputación: 0
Mensaje: #2
RE: Sobre el ConditionalValidator
(11-07-2012 11:04 AM)armando escribió:  ¿por que no se muestra ningún error si los basevalidators, A y B, detectan errores?

Si, detectan errores, pero no los muestran al usuario. Esa es la idea y ese es el comportamiento esperado. El objetivo de los basevalidators A y B es servir de condiciones para decidir si se ejecutan los subvalidadores. Imagina un caso en el que un campo no es obligatorio, pero si el usuario lo introduce entonces debe ser un número y además debe estar entre 5 y 10. En ese caso tu usas un NotEmptyValidator (con un IF) y pones el IntegerValidator y el LessThan y el GreaterThan como subvalidadores.

La idea es que si el campo está vacío entonces el NotEmptyValidator falla (puedes imaginar que evalua a false, es decir, falla=false), por lo tanto no entras en el IF y los subvalidadores no se ejecutan. Es decir, el campo está vacío, por lo tanto no vale la pena validar si es un número y si está en el rango correcto.

En el caso de que el NotEmptyValidator pase (puedes imaginar que pasar=true), entonces si entras en el IF y los subvalidadores se ejecutan. Aquí hay que ver que pasa luego, es decir, depende si chained=true o false). Aquí dependiendo de eso puede pasar que al detectar que el campo NO es un entero se aborta la ejecución de los siguientes validadores (el orden en que los añades es importante). La otra opción es que se ejecuten todos los validadores en cascada, lo que te lleva a una situación en que si no tienes un número entonces hay que ver como se comporta el LessThan / GreaterThan (se estrellan, se evalúan, etc).

(11-07-2012 11:04 AM)armando escribió:  dependiendo del tipo de validación por supuesto. La cuestión es que en caso tal, de que los basevalidators detecten errores, no se mostrara ningún mensaje al usuario al momento de validar un campo, todos los mensajes de error se delegan a los subvalidadores. Entonces si hay algún error en realidad a nivel de los basevalidators el usuario no se va a enterar de nada?

Exacto, esa es la idea. Los baseValidators no son para mostrar mensajes de error, son para decidir si se evalúan o no los subvalidadores.

(11-07-2012 11:04 AM)armando escribió:  La pregunta y la propuesta, en este caso, es dejar la implementación del ConditionalValidator tal cual como esta, que ya esta probado que funciona, encadenando validadores y todo. Pero Mi propuesta es quitar esos basevalidators del constructor de la clase, y esos mismos baseValidators convertirlos en los propios subvalidadores efectivos. De manera que efectivamente se construya un validador condicional que muestre todo los mensajes de error dependiendo de la condición elegida.

Esto no tiene sentido, porque precisamente rompe toda la semántica y toda la idea del ConditionalValidator.



Propongo definir una notación para poder hablar de esto en el foro de forma abstracta sin preocuparnos mucho por el código. Esto es sólo una propuesta, y es sólo una notación para comunicarnos en el foro, si les confunde podemos seguir con código. La notación va a ser así (Tipo Arbol):

Código:
Validador1
Validador2
...
ValidadorN

Estos son validadores de primer nivel. Es decir, todos se añaden al fieldModel con:

Código:
getValidatorList().add(new Validator1());
getValidatorList().add(new Validator2());
...
getValidatorList().add(new ValidatorN());

Luego podemos decir algo como:

Código:
CV (IF ValidatorBA1)
  Validator1
  Validator2
  ...
  ValidatorN
CV (AND ValidatorBA10, ValidatorBB10)
  Validator10
  Validator20
  ...
  ValidatorNN

Eso significa dos ConditionalValidators añadidos al FieldModel, el primero un IF con ValidatorBA1 como BaseValidatorA y el segundo con un AND con ValidatorBA10 y ValidatorBB10 como BaseValidatorB, con Validator10, 20 hasta NN como subvalidadores.

Con esa notación, por ejemplo podemos escribir cosas como:

Código:
CV (IF NotEmpty)
  NumberValidator
  GreaterThan 5
  LessThan 10

Eso significa algo como:

Código:
ConditionalValidator cv = new ConditionalValidator(IF, new NotEmptyValidator());
getValidatorList().add(cv);

cv.add(new NumberValidator());
cv.add(new GreaterThanValidator());
cv.add(new LessThanValidator());

Por ejemplo, nos permite escribir fácilmente cosas como:

Código:
CV (AND NotEmpty, NumberValidator)
  NumberValidator
  GreaterThan 5
  LessThan 10

Y evaluar opciones, por ejemplo, que es mejor, lo anterior o esto:

Código:
CV (IF NotEmpty)
  NumberValidator
  CV (IF NumberValidator)
    GreaterThan 5
    LessThan 10

En principio se deberían comportar igual... (depende del chainend).

Algo que me estoy dando cuenta, que se puede resolver, es que hay cierta duplicación. Es decir, es evidente que NumberValidator en los dos ejemplos anteriores está repetido dos veces (se le va a hacer new dos veces). Esto pareciera ser un problema general en la idea (creo que eso es lo que les hace sentirse incómodos y no entender bien lo de los BaseValidators). Creo que ha sido algo bueno detectar (y dejar documentado) este problema, es algo que mejorar, aunque no creo que valga la pena intentarlo ahora).

Quizá una propuesta es que un ConditionalValidator OPCIONALMENTE pueda no solo usar sus BaseValidator para evaluar si ejecuta los hijos sino que también en algunos casos, como ya dije, opcionalmente, pueda también mostrar un mensaje de error al usuario. Eso tendría sentido en el caso anterior, que podría quedar como:

Código:
CV (IF NotEmpty)
  CV (IF NumberValidator, TRUE) <--- Este true podría significar "mostrar al usuario"
    GreaterThan 5
    LessThan 10

Como pueden ver eso eliminaría la duplicidad (y es una solución fácil Wink )

En fin, ahí quedan algunas ideas, dependiendo de lo que sigan escribiendo/preguntando continúo escribiendo luego.

[Imagen: dmi-1.jpg]
11-07-2012 08:13 PM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Gerardo Garcia Sin conexión
Boss

Mensajes: 3
Registro en: Apr 2011
Reputación: 0
Mensaje: #3
RE: Sobre el ConditionalValidator
Hola profesor,

Bueno lei la respuesta que le dio a Armando y esta clara la funcionalidad del ConditionalValidator que es de servir de condiciones para decidir si se ejecutan los subvalidadores mas no mostrar mensajes de error. Pero entonces para casos particulares como se codificaria?

Ejemplo:
Validar el campo Numero en donde lo que se desea es mostrar un mensaje de error pero validar primero que no este vacio y sino entonces validar que sea un numero, como esta codificado actualmente es asi:

Código:
ConditionalValidator VN1 = ConditionalValidator
                .IF(new     NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(),
                        txtNumero));

            VN1.add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.numero(),
                txtNumero));

//        fmNumero.getValidatorList().add(
//                new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(),
//                        txtNumero));

        fmNumero.getValidatorList().add(VN1);

        sectionModel.addChild(fmNumero);

Lo que esta comentado es la parte que se comento durante la exposicion. Pero quiero aclarar que la idea es conseguir la solucion al manejo de la visualizacion de los mensajes de error.

El caso especifico seria que si esta vacio el campo, entonces solo muestre que esta vacio, y si contiene algo pero no es un numero entonces que muestre el mensaje que diga que debe ser un numero.



Por otro lado, otro ejemplo a tomar en cuenta es el de rango el cual esta codificado actualmente de la siguiente manera:
Código:
        ConditionalValidator VR1 = ConditionalValidator
                .AND(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.rango(),
                        txtRango),
                        new IntegerValidator(_I18NFrmMCrudPruebaEdit.rango(),
                                txtRango), false);

        VR1.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 5));
        VR1.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 11));
        VR1.add(new LowerThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 20));

//        fmRango.getValidatorList()
//                .add(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.rango(),
//                        txtRango));
//
//        fmRango.getValidatorList()
//                .add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.rango(),
//                        txtRango));

        fmRango.getValidatorList().add(VR1);

Pero de nuevo es el mismo caso (de igual forma esta comentada la seccion que se implemento para que funcionara el manejo de mensajes de error), lo unico que estamos considerando ahora el codicional AND en donde lo que se quiere es que validar ambas condiciones (que no este vacio y que sea un numero) y que si pasan entonces validar si es mayor o menor que algo; es importante tomar en cuenta que tambien se quiere mostrar mensaje si esta vacio o no, pero de manera individual y no por lotes de mensajes de error.



Para los dos ejemplos anteriores, al encontrar una buena solucion se puede mejorar esto ya que se entiende la finalidad del CoditionalValidator pero para nuestros casos especificos aun no hemos podido encontrar lo ideal (mostrar un mensaje de error a la vez, ej.: si esta vacio, que muestre que esta vacio solamente, y que no muestre: que esta vacio y que tiene que ser numerico) sin tener que editar el codigo base. En la exposicion me menciono que a lo mejor incluyendo un IF dentro del ConditionalValidator o algo asi se pudiese solucionar pero esa parte no quedo especificamente clara.
11-07-2012 09:42 PM
Encuentra todos sus mensajes Cita este mensaje en tu respuesta
demian Sin conexión
Administrator
*******

Mensajes: 1.808
Registro en: Jun 2010
Reputación: 0
Mensaje: #4
RE: Sobre el ConditionalValidator
(11-07-2012 09:42 PM)Gerardo Garcia escribió:  Validar el campo Numero en donde lo que se desea es mostrar un mensaje de error pero validar primero que no este vacio y sino entonces validar que sea un numero, como esta codificado actualmente es asi:

Código:
ConditionalValidator VN1 = ConditionalValidator.IF(
  new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));

VN1.add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));

fmNumero.getValidatorList().add(VN1);

Esto tal como está se debería comportar así:

1) El campo NO ES obligatorio, puede estar vacío.
2) Si el campo tiene algo, entonces valida que ese "algo" sea un número.

En conclusión: Campo vacío no hay mensaje de error. Campo lleno, si es un número no hay mensaje de error. Campo lleno, si no es un número dice "El campo X debe ser un entero".

(11-07-2012 09:42 PM)Gerardo Garcia escribió:  Lo que esta comentado es la parte que se comento durante la exposicion. Pero quiero aclarar que la idea es conseguir la solucion al manejo de la visualizacion de los mensajes de error.

El caso especifico seria que si esta vacio el campo, entonces solo muestre que esta vacio, y si contiene algo pero no es un numero entonces que muestre el mensaje que diga que debe ser un numero.

Entiendo que lo que quieres es:

1) El campo SI ES obligatorio, si está vacío debe decir "El campo X es obligatorio".
2) Igual que en el caso anterior.

Eso sería así:
(¡¡¡¡Ya me acorde!!!!, CLEDA si tiene un mecanismo para hacer esto Wink )

Código:
ConditionalValidator VN1 = ConditionalValidator.CHAIN();

VN1.add(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));
VN1.add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));

fmNumero.getValidatorList().add(VN1);

Si chained es true (que es lo que hace CHAIN) entonces se detiene en el primer mensaje de error, es decir, en el primer subvalidador que encuentra que falla. Si chained es false los evalúa a todos.

Noten que muchos de los métodos de ConditionalValidator retornan un ConditionalValidator. Esto permite encadenar las llamadas para no tener que declarar variables intermedias (como VN1). Por ejemplo, el código anterior debería poderse escribir en uno sola (y larga) línea de código:

Código:
fmNumero.getValidatorList().add(ConditionalValidator.CHAIN().add(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero)).add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero)));

Por eso es que add retorna un ConditionalValidator y por eso es que existen métodos estáticos IF, CHAIN, NOT, AND y OR (que también retornan un ConditionalValidator). Revisen con cuidado esos métodos y compárenlos con el ejemplo anterior y verán a que me refiero.

Por cierto que esto es parte de la clave para generar esto desde el XML, eso se los respondo en la noche en el otro post.



(11-07-2012 09:42 PM)Gerardo Garcia escribió:  Por otro lado, otro ejemplo a tomar en cuenta es el de rango el cual esta codificado actualmente de la siguiente manera:
Código:
        ConditionalValidator VR1 = ConditionalValidator
                .AND(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.rango(),
                        txtRango),
                        new IntegerValidator(_I18NFrmMCrudPruebaEdit.rango(),
                                txtRango), false);

        VR1.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 5));
        VR1.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 11));
        VR1.add(new LowerThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
                txtRango, 20));

//        fmRango.getValidatorList()
//                .add(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.rango(),
//                        txtRango));
//
//        fmRango.getValidatorList()
//                .add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.rango(),
//                        txtRango));

        fmRango.getValidatorList().add(VR1);

Pero de nuevo es el mismo caso (de igual forma esta comentada la seccion que se implemento para que funcionara el manejo de mensajes de error), lo unico que estamos considerando ahora el codicional AND en donde lo que se quiere es que validar ambas condiciones (que no este vacio y que sea un numero) y que si pasan entonces validar si es mayor o menor que algo; es importante tomar en cuenta que tambien se quiere mostrar mensaje si esta vacio o no, pero de manera individual y no por lotes de mensajes de error.


Esto también se puede resolver con lo que acabo de recordar. Quizá sería algo así:

Código:
ConditionalValidator VN1 = ConditionalValidator.CHAIN();

ConditionalValidator VN2 = ConditionalValidator.CHAIN();
VN2.add(new NotEmptyValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));
VN2.add(new IntegerValidator(_I18NFrmMCrudPruebaEdit.numero(), txtNumero));

VN1.add(VN2)

ConditionalValidator VN3 = ConditionalValidator.CHAIN(false);

VN3.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
    txtRango, 5));
VN3.add(new GreaterThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
    txtRango, 11));
VN3.add(new LowerThanValidator(_I18NFrmMCrudPruebaEdit.rango(),
    txtRango, 20));

VN1.add(VN3)

fmNumero.getValidatorList().add(VN1);

Tiene lógica, ¿no creen? Wink ... a ver, me explico.

El validador raíz (VN1) es encadenado (chained = true). Esto significa que al encontrar un subvalidador que genera errores entonces deja de ejecutar los siguientes validadores. El validador raiz tiene DOS subvalidadores, y ambos son ConditionalValidators.

El primer ConditionalValidator (VN2) es encadenado y valida que el campo NO este vacío y que SI sea un número. Si el campo está vacío, no se valida que sea un número (porque es encadenado y falla el primer subvalidador de VN2). Si el campo NO esta vacío y SI es un número ninguno de los subvalidadores de VN2 falla, por lo tanto VN2 en si mismo NO FALLA (porque no retorna ningún mensaje de error). Como VN2 no falla en este caso, VN1 pasa a ejecutar VN3.

VN3 no está encadenado (chained=false), lo que significa que va a ejecutar TODOS sus subvalidadores independientemente del resultado de cada uno de ellos (que es lo que se quiere, es decir, si el campo no está vacío y es un entero entonces quiero validar todos los rangos posibles, para mostrarle los dos mensajes de rango al mismo tiempo al usuario).

Si quieren, lo pueden analizar usando un árbol (es sólo una notación):

Código:
VN1 (chained = true)
  VN2 (chained = true)
    NotEmpty
    Integer
  VN3 (chained = false)
    GreaterThan 5
    GreaterThan 10
    LessThan 20
[code]

Si lo ven de esa forma el comportamiento está muy claro.

Por cierto que es buen momento para decir que en:

[code]
fmAlgo.getValidatorList().add(algunValidador);

Nunca se implementó el chained directamente porque la idea era NO sobrecargar al FieldModel con eso y pasar la responsabilidad de eso al ConditionalValidator. ¿Se acuerdan que en clase ayer dijimos que debía haber una forma de hacerlo, que me dejaran revisar? Bueno, usando el ConditionalValidator tal como ya he mencionado es exactamente la forma, eso fue lo que recordé hoy escribiendo este post.



(11-07-2012 09:42 PM)Gerardo Garcia escribió:  Para los dos ejemplos anteriores, al encontrar una buena solucion se puede mejorar esto ya que se entiende la finalidad del CoditionalValidator pero para nuestros casos especificos aun no hemos podido encontrar lo ideal (mostrar un mensaje de error a la vez, ej.: si esta vacio, que muestre que esta vacio solamente, y que no muestre: que esta vacio y que tiene que ser numerico) sin tener que editar el codigo base. En la exposicion me menciono que a lo mejor incluyendo un IF dentro del ConditionalValidator o algo asi se pudiese solucionar pero esa parte no quedo especificamente clara.

Creo que el problema está resuelto y que no hay que cambiar nada ni en el FieldModel ni en el ConditionalValidator. Revisen con mucho cuidado este post, si aún hay algo que no se entienda me avisan, hagan pruebas, verifiquen el como funciona y cualquier cosa me avisan. Y si todo está OK, ¡documenten, hagan ejemplos, pongan estos ejemplos particulares, etc!

Me parece que el formulario de validación les está quedando ya pequeño, capaz que lo tienen que picar en dos o tres formas distintas más simples. Al menos una que muestre el uso básico de los validadores y quizá una o dos que muestren el uso de estas características avanzadas.

Cualquier cosa gritan, en la noche respondo el otro post.

PS: ¡Estos posts, y la documentación generada valen oro! Por eso es que los fastidio tanto con el foro y la wiki. ¿Se dan cuenta?

[Imagen: dmi-1.jpg]
12-07-2012 01:10 PM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Enviar respuesta 


Salto de foro:


Usuario(s) navegando en este tema: 1 invitado(s)