sábado, 4 de febrero de 2017

Personalizar los correos de los flujos de trabajo en HTML

Desde versiones anteriores como SharePoint 2007 hemos podido personalizar el cuerpo de los correos, con la apariencia que deseábamos mediante su personalización con código HTML.

En versiones como SharePoint 2007, bastaba con poner el código HTML en el cuerpo del correo electrónico. Pero sí hacemos eso en la versión 2013 no obtendremos el mismo resultado.


Para ello, deberemos acceder desde las Propiedades de la acción Enviar por correo electrónico:


En la ventana que se nos abrirá tendremos la opción de poder editar el cuerpo del correo a nuestro gusto:


Eso nos abrirá la ventana de generador de cadenas, donde podremos poner todo el código HTML y CSS que deseemos, pudiendo personalizar el cuerpo del correo, de una manera más rica que la permitida por la barra de edición del cuerpo del correo, que nos facilita SharePoint Designer:

sábado, 28 de enero de 2017

Campos dependientes en SharePoint

Esta es una entrada que tal vez debiera haber hecho hace mucho tiempo. Una de las limitaciones que más sorprende a la gente cuando se acerca por primera vez a SharePoint, es el hecho de que no se pueda establecer una dependencia entre los campos de tipo elección.

La verdad es que es una gran limitación en el día a día. Por suerte, como siempre tenemos JQuery y en este caso en concreto SPServices.

Uno de mis clientes nos solicito un formulario para etiquetar empresas que ofrecían servicios, clasificables en tres niveles, niveles dependientes entre ellos.

Lo primero que tuve que hacer es una lista con los valores del primer nivel:

Tras ello, crearemos otra lista, que tendrá un campo de tipo texto, donde irán los valores del segundo nivel, y un campo de tipo búsqueda que buscará sobre la columna de la primera lista:

Y de manera análoga el para el tercer nivel:

Estas serán nuestras tres listas maestras, desde donde podremos gestionar los valores de los tres campos de elección. Lo siguiente que haremos será crear tres columnas de tipo búsqueda, en la lista donde queremos utilizar los valores:

Cada una de las columnas, buscará sobre la lista correspondiente a su nivel, eligiendo al crearlas, si son de valor único o múltiple selección (en mi caso los tres son de múltiple selección):
Y por último tendremos que añadir en los formularios que deseemos que se comporten como campos dependientes el siguiente código:

<script type="text/javascript">
$(document).ready(function() {
$().SPServices.SPCascadeDropdowns({
relationshipList: "Nivel 2",
relationshipListParentColumn: "Nivel",
relationshipListChildColumn: "Title",
parentColumn: "Listado1",
childColumn: "Listado2";
});  
$().SPServices.SPCascadeDropdowns({
relationshipList: "Nivel 3",
relationshipListParentColumn: "Nivel",
relationshipListChildColumn: "Title",
parentColumn: "Listado2",
childColumn: "Listado3";
});
});
</script>

En la primera llamada a SPCascadeDropdowns, lo que se indica es la lista sobre la que se va a filtrar el valor, en nuestro caso Nivel 2, que es donde se encuentra la relación. Lo siguiente que diremos es sobre que columna de esa lista va a actuar como Padre y cual sobre Hijo, es decir, cual la que nos permite seleccionar el valor para filtrar y sobre cual se filtran los valores. Por último, indicaremos sobre que campos de nuestra actual lista actuará.

En la segunda llamada a SPCascadeDropdowns, se repite la operación pero sobre el segundo y tercer valor.

Quedando un funcionamiento de campos dependientes:

NOTAS: 

  • Se da por supuesto, que en la página maestra o bien en el código de la página, se encuentra una referencia a JQuery y otra SPServices.
  • Los líneas relationshipListParentColumn: "Nivel" y relationshipListChildColumn: "Title", hacen referencia al Nombre interno del campo en la lista donde hacemos la relación "Nivel 2". De hecho, en mi ejemplo, como utilizo SharePoint en Español, el nombre externo es Título y no Title.
  • Las segundas referencias parentColumn: "Listado1" y childColumn: "Listado2", hacen referencia al nombre a mostrar de la columna y no al nombre interno.
  • En esta última referencia, si un campo es obligatorio, la referencia debe ser de la forma: parentColumn: "Listado1 Campo requerido", que corresponde con el title en HTML del campo. En mi caso es Campo requerido, porque mi SharePoint esta en Español, si lo tenéis en Inglés, posiblemente sea Requiered field.


Fuentes:
http://sympmarc.github.io/SPServices/value-added/SPCascadeDropdowns.html
http://www.bentedder.com/sharepoint-sketches-spservices-cascading-dropdowns/

sábado, 17 de diciembre de 2016

Comprobaciones antes de guardar (PreSaveItem)

Muchas veces me encuentro con el escenario en el que en una lista se precargan unos valores y luego a través del formulario de edición queremos que otra persona complete otros datos.
En esta situación puede ser que nos interese que algún campo sea obligatorio. Sí en una lista de SharePoint marcamos un campo como obligatorio, nos obligará a cargarle un valor cuando lo creamos, en lugar de edición. Para ello, podemos utilizar la función PreSaveItem:

function PreSaveItem()
{
var save = false;
var area = $( "[title*='Area'] option:selected" ).text();
var centro = $( "[title*='Centro'] option:selected" ).text();
if (area != '(Ninguno)' && centro != '(None)'){
            save = true;
}else if(area == '(Ninguno)'){
alert('Seleccione un área');
}else if(centro == '(None)'){
alert('Seleccione un centro');
}
return save;
}

Al incluir el código superior, lo que hacemos es llamar a una función en la que en este caso en concreto, lo que hacemos es recoger el valor seleccionado en dos campos de tipo elección a los cuales le hemos aplicado SPServices para que se comporten como campos en cascada.

Y comparamos que no tomen el valor (Ninguno) para el campo area, ni (None) para el campo centro, si tienen valor en esos campos, devolveremos el valor true, que permitirá que se guarde, sino devolverá false, lo que hará que no se guarden los valores y gracias a los alert mostraremos un mensaje al usuario indicándole que campo se le ha olvidado completar.

sábado, 12 de noviembre de 2016

Mostrando el nombre de un archivo y enlazarlo en una vista de datos

Anteriormente ya hice una entrada de como mostrar los iconos de los documentos en una vista de datos.

Pues bien, otra cosa que me suelen pedir mucho y que va justo detrás del icono, es mostrar el nombre del documento y el enlace al mismo. Lo que viene siendo el comportamiento propio de SharePoint.

Para una vista de datos, basta con poner:

<a href="{@FileRef}">
<xsl:value-of select="@FileLeafRef.Name" />
</a>

Y nos pondrá la URL relativa, lo cual es muy útil, si tenemos diferente URL desde dentro que desde fuera y nos mostrará el nombre del archivo sin acabar en la extensión.

domingo, 18 de septiembre de 2016

Detener la carga de una página durante X segundos para esperar por un flujo de trabajo

 Esta semana he tenido que hacer una relación entre dos listas y para enlazar la primera con la segunda he tenido que crear el enlace en una columna oculta con un flujo de SharePoint.

El problema era que se cargaba más rápido la nueva página donde se mostraba el enlace, que el flujo nos completará el campo.

La solución que se me ha ocurrido (posiblemente no sea la mejor), es meter en el head un retardo de 2 segundos y recargar la página. Con el fin de evitar un bucle infinito, una vez espero, le añado a la URL de la página el carácter #.

Lo que he hecho, ha sido buscar con el Designer en el código de la página el bloque:

<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">

Y si no, bastaría con crearlo abriendo y cerrando la etiqueta. Para posteriormente incluir en él:

<SharePoint:ScriptBlock runat="server">
    
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
var url = window.location.href;
 if(url.indexOf("#")!= -1){
 
 }else{
  sleep(2000);
  var nurl = window.location.href;
  nurl = nurl+"#";
  window.location.href = nurl;
  location.reload();
 }


</SharePoint:ScriptBlock>

domingo, 21 de agosto de 2016

Recoger parámetro de la URL con Jquery y completar un campo de tipo búsqueda de SharePoint

 Siguiendo con la entrada anterior quedaría recoger el número de ID correspondiente al libro y dejarlo seleccionado en un campo de tipo búsqueda de la lista reserva de libros. Dicho campo, será un campo de búsqueda sobre la lista de libros, cogiendo como clave el nombre del libro.

Para ello tendremos una dirección del tipo:

https://URLdelSitio/Lists/ReservaLibro/Nuevo.aspx?Libro=1&Source=/URLdelSitioalquevolvertrasaceptar/

Este sería el libro con el ID=1 en la lista de libros.

Para ello, en formulario de nuevo elemento de la lista reserva de libros, debería añadir un editor de código fuente con el siguiente código:

<script>

$(document).ready(function(){

var direccion = window.location.href;

var numero = direccion.split('Libro=')[1];

                 numero = numero.split('&Source')[0];

$("[title='Libro'] option[value="+numero+"]").prop('selected', true);

$('#Book option:not(:selected)').attr('disabled',true);

});

</script>

Habiendo añadido el ID=Book al tr del campo de busqueda, en mi caso:

<td width="400px" valign="top" class="ms-formbody" id="Book">

<SharePoint:FormField runat="server" id="ff3{$Pos}" ControlMode="New" FieldName="Libro" __designer:bind="{ddwrt:DataBind('i',concat('ff3',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Libro')}"/>

<SharePoint:FieldDescription runat="server" id="ff3description{$Pos}" FieldName="Libro" ControlMode="New"/>

</td>

El código JavaScript de arriba lo que hace es:

  1. Recoger la URL en la variable dirección
  2. Quedarnos con la parte tras la palabra 'Libro=' en la variable numero
  3. En esa misma variable, eliminamos la parte del redireccionamiento
  4. Buscamos el campo de tipo búsqueda, que en mi caso se llama Libro y seleccionamos el valor que hemos recogido de la URL en la variable numero
  5. Por último, deshabilitamos el resto de opciones diferentes a la que hemos pasado como parámetro del Libro.
Está última parte, fue para la cual tuve que buscar en Google, ya que si hacía que el campo estuviera en disable no me guardaba el valor correcto y al ser un campo de elección no tenía sentido ponerlo en readonly.
Encontré esta entrada, que me dio la solución:



domingo, 31 de julio de 2016

Completar campo de tipo hipervínculo con un flujo

Recientemente me han pedido realizar una lista de libros y otra lista para la reserva de libros.

Para la primera parte, simplemente he creado una listas con los campos correspondientes: Nombre, Autor, ISBN, Resumen y un campo oculto de tipo hipervínculo que se asoma en las vistas llamado inscripción.

Este campo llevará un enlace a la lista de reserva de libros, en el que se pasará el ID del libro en cuestión que se quiere reservar.

Para ello, crearemos un flujo que se lance cuando se crea o se modifica un elemento. En el que crearemos una variable de tipo Cadena, para guardar la URL del enlace:


Estableceremos en dicha variable, la URL del enlace al elemento de Nuevo de la lista reserva de libros, donde le pasaremos como parámetro el ID del elemento en la lista de libros y separaremos la URL del nombre a mostrar por una coma y un espacio en blanco (, ) como por ejemplo:
 

Finalmente bastaría con guardar la variable del flujo, en nuestro campo de tipo hipervínculo:


En la siguiente entrada continuo con la parte de recoger el parámetro pasado desde la lista reserva de libros, con Jquery.