WSS 3.0 & MOSS: Construyendo vistas avanzadas con SharePoint Designer 2007 (III)!

Siguiendo con la serie de post de construcción de aplicaciones de SharePoint utilizando SharePoint Designer 2007 como herramienta y entorno de desarrollo, en este post vamos a ver como dotar de funcionalidad al formulario de inserción de datos que añadimos en el último post. Si recordamos el aspecto de la página de vista de datos finalmente desplegada:

image

Como veíamos en el post previo, esta página permite insertar datos en la BD SQL Server mediante el formulario de inserción, estos datos insertados se visualizan de manera automática en la web part correspondiente. Además, también veíamos como conectar en el entorno de SD 2007 distintas web parts para que funcionaran de manera coordinada. Ahora bien, y a raíz de que me haya planteado la cuestión por e-mail, está página se puede mejorar aún más en cuanto a que podamos añadirle validaciones al formulario de inserción de datos. El problema de realizar validaciones para este formulario de inserción es que tenemos que tener en cuenta que se trata de nuestra vieja amiga la Data Form Web Part, por lo que para añadir la validación vamos a tener que recurrir a utilizar JavaScript…si además tenemos en cuenta que el entorno de desarrollo es SD 2007 (un dolor…), pues resulta que construir esta sencilla validación puede dar más de un quebradero de cabeza. Por suerte, en la red (y aunque hay pocos recursos sobre este tema), hay un par de artículos a partir de los cuáles he podido construir la lógica de validación:

Ahora bien, aunque estos recursos han sido claves para saber como atacar el problema, en mi caso (y muchos otros) me ha llevado un buen rato llegar a una solución operativa y en funcionamiento debido a las peculiaridades de la Data Form Web Part y la estructura XSL que “escupe” y que es muy sensible a carácteres especiales. Empecemos.

Modelando la solución

Tal y como se comenta en los dos enlaces que os he indicado, y sobre todo en el segundo, el principal problema que hay que superar es como añadir un evento  a alguno de los botones que genera la Data Form Web Part en el momento en el que estamos añadiendo una vista de datos desde SD 2007 de acuerdo a la opción New Form (ver post anterior) debido a que no exponen de manera pública un evento que se pueda programar. Como nos comenta Fabián Imaz, la solución a este problema es aprovecharnos de la función AttachEvent de JavaScript que nos permite, y para Internet Explorer (restricción importante!), registrar eventos para controles y especificar la función JavaScript que se encargará de manejar dicho evento (Por cierto, para Firefox la función JavaScript equivalente es addEventListener). Una vez que sabemos como registrar un evento para un control, el siguiente paso es elegir el evento que vamos a registrar. De nuevo me remito a Fabián y su excelente entrada para constar de que no podemos registrar el evento click porque el formulario ya habrá pasado por el proceso de Submit y por lo tanto no se puede cancelar el proceso (en este caso se trata del proceso de guardar los datos en la BD). Entonces como alternativa, podemos utilizar otro evento típico para controles tipo botón o imágenes como es el onmouseup o el onmouseover (que es el que voy a utilizar en mi caso).

Una vez que sabemos como registrar el evento para un control y hemos elegido el evento que vamos a registrar, necesitamos una forma de obtener el control especifico al que vamos a añadirle este evento. Para ello, tenemos los métodos getElementById o getElementByName.

Finalmente, necesitamos saber dónde colocar todo el código JavaScript que vamos a utilizar para registrar los eventos de los controles, así como añadirlo en el evento Load de la carga del formulario. Para el primer punto, no conozco una regla fija, sino que simplemente hay que pensar en XSLT y lo delicado que es para saber dónde colocar todo el código JavaScript. En mi caso, y por intuición, lo he colocado a continuación de los botones a los que quiero registrar el evento y antes del tag </xsl:template> (por cierto, este post puede resultar esclarecedor para comprender la estructura XSL de la Data Form Web Part):

<xsl:template name=”dvt_1.formactions”>

                                               <td nowrap=”nowrap” class=”ms-vb”>

                                                                      <input type=”button” value=”Save” name=”btnSave” onclick=”javascript: {ddwrt:GenFireServerEvent(‘__commit’)}” />

                                               </td>

                                               <td nowrap=”nowrap” class=”ms-vb” width=”99%”>

                                                                      <input type=”button” value=”Cancel” name=”btnCancel” onclick=”javascript: {ddwrt:GenFireServerEvent(‘__cancel’)}” />

                                               </td>

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

//Código JavaScript

</script> </xsl:template>

Y para el segundo de los puntos, añadir todo este código JavaScript a la pila de funciones JavaScript que dispara el evento Load de la página dónde se embebe el formulario tenemos la función JavaScript siguiente:

_spBodyOnLoadFunctionNames.push(“EventButton”);

Una vez modelada la validación, vamos a ver como implementarla.

Implementando la validación

Lo primero que tenemos que hacer es llamar a la función JavaScript anterior que se encarga de añadir la función EventButton a la pila de funciones JavaScript de la página. Una vez que hemos hecho esto, creamos la función y en la misma tenemos que hacer lo siguiente:

  • Declarar dos objetos que se correspondan con los controles (los botones Save y Cancel del formulario) a los que les vamos a registrar los eventos.
  • Encontrar estos objetos entre toda la colección de controles del formulario. Para ello utilizaré la función getElementById, puesto que para el caso de los botones SharePoint devuelve un ID limpio (lo que no sucede con los controles de tipo caja de texto).
  • Registrar mediante attachEvent el evento onmouseover para cada control y especificar la función que se encargará de manejarlo.

El código necesario para realizar todo lo anterior es el siguiente:

function EventButton()

{

                       PonerFocoInicial();

                       var objAceptar=document.getElementById(“btnSave”);

                       objAceptar.attachEvent(“onmouseover”,Aceptar); 

                       var objCancelar=document.getElementById(“btnCancel”);

                       objCancelar.attachEvent(“onmouseover”,Cancelar);

}

Nota: En el código he añadido una función adicional PonerFocoInicial() que simplemente pone el foco del cursor en una de las cajas de texto del formulario.

Una vez que hemos registrado los eventos y añadido los manejadores, el siguiente paso es definir estos últimos:

  • Manejador Cancelar: Simplemente mostrará por pantalla un mensaje infomativo (utilizando alert()).

function Cancelar()

{

                       var ICancelarEvento=false;

                       alert(“Cancelada la insercción de un nuevo curso”);

                       return ICancelarEvento;

}

  • Manejador Aceptar, que es dónde introduciremos la lógica de validación. Lógicamente es aquí dónde empiezan las complicaciones, y dónde más quebraderos de cabeza me he llevado, puesto que para buscar el control a comprobar no tenemos una referencia clara como ocurre con los botones…de hecho, el ID de una caja de texto tiene la siguiente forma:

ctl00$m$g_5437d929_64a3_4a68_be70_f2452c6f6981$ff2_new

Vamos, que además de que a priori no conoces el valor de este ID, y encima es bastante feo. Sin embargo, si nos fijamos en el ID, si que hay una parte que se corresponde con el ID que aparece en SD 2007 cuando examinamos los controles que ha generado la Data Form Web Part: ff2_new. Y de esto nos aprovechamos para utilizar la función getTagFromIdentifierAndTitle que aparece en el post que os comenté del equipo de SD 2007 (si bien, y como os explicaré, he tenido que modificar la función getTagFromIdentifierAndTitle para que funcione correctamente encajada dentro del XSL de la Data Form Web Part). No me enrollo más…el código del manejador Aeptar es el siguiente:

function Aceptar()

{

                       var ICancelarEvento=false;

                       var lsNombreProducto=null;

                       lsNombreProducto=document.getElementById(getTagFromIdentifierAndTitle(“input”,”ff2_new”,””));

                       if(lsNombreProducto.value==””)

                       {

                                               alert(“EL campo Nombre Producto no puede estar vacío!”);

                                               lsNombreProducto.focus();

                       }                     

                       return ICancelarEvento;

}

Cómo veis en la función anterior, la clave para encontrar el control a validar está de nuevo en el método getElementById dentro de la cuál se llama a la función getTagFromIdentifierAndTitle que recibe como parámetros el tipo de control y la cadena de texto a buscar entre los ID de la colección de controles del formulario. El código de dicha función es el siguiente:

function getTagFromIdentifierAndTitle(tagName, identifier, title)

{

    var len = identifier.length;

    var tags = document.getElementsByTagName(tagName);   

    for (var i=0;i&lt;tags.length;i++) {

        var tempString = tags[i].id;

       

        if (tags[i].title == title &amp;&amp; (identifier == “” || tempString.indexOf(identifier) == tempString.length – len))

        {

            return tempString

        }

    }

}

En este caso, lo más peculiar de esta función es que debido a la sensibilidad de XSL, en el bucle for he tenido que usar la representación estándar HTML del símbolo < pues SD 2007 y SharePoint no admiten que especifiques este símbolo a no ser que indique un tag. Dentro del bucle for que recorre todos los controles del formulario (y que almaceno en el objeto tags, que he “rellenado” mediante la método getElementsByTagName) simplemente busco aquel control cuyo ID contenga la palabra clave que le he pasado a la función y lo devuelvo (por cierto, fijaros de nuevo que en el if he tenido que reemplazar && por &amp;&amp; por lo mismo que antes).

  • Función PonerFocoInicial, esta es la más sencilla de todas una vez explicado lo anterior ;):

function PonerFocoInicial()

{

                       var ICancelarEvento=false;

                       var lsNombreProducto=null;

                       lsNombreProducto=document.getElementById(getTagFromIdentifierAndTitle(“input”,”ff2_new”,””));

                       if(lsNombreProducto.value==””)

                       {                                             

                                               lsNombreProducto.focus();

                       }                     

                       return ICancelarEvento;

 

}

Juntándolo todo y probando la validación

Sin más, vamos a probar que toda la validación funciona de manera correcta. Para ello, desde SD 2007 hacemos  un Preview de la página:

  • Al pasar el ratón por el botón Save, aparece el mensaje de que no se ha introducido un cierto dato.

image

  • Al pasar el ratón por el botón Cancel, aparece el mensaje correspondiente.

image

Para concluir este post, el código completo encajado en la estructura XSL de la Data Form Web Part es:

<xsl:template name=”dvt_1.formactions”>

                                               <td nowrap=”nowrap” class=”ms-vb”>

                                                                      <input type=”button” value=”Save” name=”btnSave” onclick=”javascript: {ddwrt:GenFireServerEvent(‘__commit’)}” />

                                               </td>

                                               <td nowrap=”nowrap” class=”ms-vb” width=”99%”>

                                                                      <input type=”button” value=”Cancel” name=”btnCancel” onclick=”javascript: {ddwrt:GenFireServerEvent(‘__cancel’)}” />

                                               </td>

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

// Esta función es propia de Sharepoint y nos permite poner

//una función nuestra dentro de la pila de funciones que serán disparadas en el evento Load del mismo cuando

//se carge.

 _spBodyOnLoadFunctionNames.push(“EventButton”);

function EventButton()

{

                       PonerFocoInicial();

                       var objAceptar=document.getElementById(“btnSave”);

                       objAceptar.attachEvent(“onmouseover”,Aceptar); 

                       var objCancelar=document.getElementById(“btnCancel”);

                       objCancelar.attachEvent(“onmouseover”,Cancelar);

}

 

function getTagFromIdentifierAndTitle(tagName, identifier, title)

{

    var len = identifier.length;

    var tags = document.getElementsByTagName(tagName);   

    for (var i=0;i&lt;tags.length;i++) {

        var tempString = tags[i].id;

       

        if (tags[i].title == title &amp;&amp; (identifier == “” || tempString.indexOf(identifier) == tempString.length – len))

        {

            return tempString

        }

    }

}

function Aceptar()

{

                       var ICancelarEvento=false;

                       var lsNombreProducto=null;

                       lsNombreProducto=document.getElementById(getTagFromIdentifierAndTitle(“input”,”ff2_new”,””));

                       if(lsNombreProducto.value==””)

                       {

                                               alert(“EL campo Nombre Producto no puede estar vacío!”);

                                               lsNombreProducto.focus();

                       }                     

                       return ICancelarEvento;

} 

function Cancelar()

{

                       var ICancelarEvento=false;

                       alert(“Cancelada la insercción de un nuevo curso”);

                       return ICancelarEvento;

}

function PonerFocoInicial()

{

                       var ICancelarEvento=false;

                       var lsNombreProducto=null;

                       lsNombreProducto=document.getElementById(getTagFromIdentifierAndTitle(“input”,”ff2_new”,””));

                       if(lsNombreProducto.value==””)

                       {                                             

                                               lsNombreProducto.focus();

                       }                     

                       return ICancelarEvento; 

} 

</script> </xsl:template>

Sin más, hasta aquí llega el tercer post de la serie de creación de vistas avanzadas de datos en SharePoint con SD 2007…creo que no será el último porque mis compañeros del CIIN tienen muchas cosas en la re-cámara listas para contar.  Espero que el post os haya resultado interesante.

Publicado por

Juan Carlos González

Juan Carlos es Ingeniero de Telecomunicaciones por la Universidad de Valladolid y Diplomado en Ciencias Empresariales por la Universidad Oberta de Catalunya (UOC). Cuenta con más de 12 años de experiencia en tecnologías y plataformas de Microsoft diversas (SQL Server, Visual Studio, .NET Framework, etc.), aunque su trabajo diario gira en torno a SharePoint & Office 365. Juan Carlos es MVP de Office Servers & Services desde 2015 (anteriormente fue reconocido por Microsoft como MVP de Office 365 y MVP de SharePoint Server desde 2008 hasta 2015), coordinador del grupo de usuarios .NET de Cantabria (Nuberos.Net, www.nuberos.es), co-fundador y coordinador del Grupo de Usuarios de SharePoint de España (SUGES, www.suges.es), así como co-director de la revista gratuita en castellano sobre SharePoint CompartiMOSS (www.compartimoss.com). Hasta la fecha, ha publicado 8 libros sobre SharePoint & Office 365 y varios artículos en castellano y en inglés sobre ambas plataformas.

3 comentarios en “WSS 3.0 & MOSS: Construyendo vistas avanzadas con SharePoint Designer 2007 (III)!”

  1. Juan Carlos

    ¡¡¡ EXCELENTE !!! la seguidilla de post que haz realizado. Ademas estimado si ves mi comentario quisiera ver si es posible que me ayudes con un problema que me surgio.
    Como en este post (bueno en los tres :D) se conecto de forma logica mediante un “ID Producto”.
    Mi prgunta es como puedo hacer una consulta de datos mediante este ID Producto y que se compruebe o valide en la lista de origen o en la Base de datos y luego muestre los datos que estan asociados a este ID.
    Por ejemplo un usuario ingrese el ID producto a consultar donde presione un boton buscar, este cuando encuentre y valide el ID muestre los datos relacionados.

    Ejemplo grafico:
    Lista o Base de Datos
    ———————————-
    |ID producto | producto | valor |
    ———————————-
    | 00001 | Jueguetes | 5000 |
    | 00002 | Jardineria| 6000 |
    ———————————-

    Usuario a consultar por ID: 00001
    al comprobar el ID este debe mostrar el producto: Juguetes y su Valor: 5000.

    Espero haberme hecho entender para mi problematica y que me ayudes por favor

    Muy agradecido por tu voluntad de compartir tus conocimientos.

    Claudio Perez
    Stgo, Chile

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *