Del mismo modo que en la versión 2010 de SharePoint utilizábamos XLST y CSS para hacer cambios en el diseño de las intranets construidas en SharePoint. Ahora con el éxito del JavaScript y gracias a que cada vez son más potentes los dispositivos cliente y navegadores, cambia un poco el panorama. Por esto es que Microsoft para su versión 2013 se inventó el client-side rendering (en adelante CSR) de cara a diseñar un mecanismo para poder personalizar el estilo y diseño de las listas y bibliotecas de SharePoint usando un lenguaje algo más agradable que XSLT.
Introducción
CSR es un Framework que permite personalizar el diseño en las vistas y formularios que trae SharePoint de forma predeterminada. Digamos que este Framework aplica tanto a SharePoint 2013 como a Office 365 (al menos por ahora, febrero 2016).
Básicamente, lo que hace CSR es transformar un objeto de JavaScript en HTML y después insertarlo en el DOM.
Además, esta transformación la realiza por etapas o ámbitos según la parte de la vista o el formulario que queramos cambiar. En la figura de abajo vemos los distintos ámbitos que podemos definir a la hora de configurar una plantilla para CSR:
Para los que ya hemos trasteado con CSR y JSLink es muy importante saber que estos dos conceptos son diferentes cosas:
Ambos pueden convivir juntos, pero también el uno sin el otro. Por ejemplo, podemos asociar un JS a un XSLTListViewWebPart de SharePoint y que este fichero de JS no tenga nada de CSR y seguirá ejecutándose el código que hay dentro cuando se carga la página donde este ese webpart. Y por el contrario también podemos usar CSR directamente asociando un fichero JS a la master page usando una Custom Action, y el CSR se ejecutaría y sobrescribiría el comportamiento nativo de la vista que estemos reescribiendo.
A continuación, en este artículo veremos cómo es esta interfaz que nos proporciona Microsoft para poder sobrescribir las plantillas y registrar plantillas nuestras personalizadas.
Relación entre CSR y clienttemplates.js
En SharePoint 2013 hay un montón de ficheros de JavaScript creados con el objetivo de mejorar la experiencia de usuario. Por ejemplo, el fichero clienttemplates.js es donde está el núcleo del Framework CSR, es decir, todos los objetos, "clases" y funciones de JS que definen toda la lógica y que es cargado en las páginas de SharePoint y Office 365 de forma predeterminada. Véase en la imagen como y en qué orden se carga usando, en este caso, la plantilla de Team Site:
Lo que también es interesante es que después de clienttemplates.js se cargan otros ficheros, donde se utilizar la función RegisterTemplateOverrides, que fue previamente creada en clienttemplates.js y cuya finalidad es permitir definir una plantilla y registrarla, veremos de qué forma más adelante.
Husmeando dentro de clienttemplates.js
El fichero clienttemplates.js se encuentra, de forma predeterminada, en la ruta: C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS
Como somos muy curiosos, veamos a ver que está ocurriendo dentro de este JS. Siendo sincero, hay muchas partes de este código que no entiendo y que no he tenido tiempo de investigar, pero veamos un poco las partes más importantes. Estas son las primeras líneas de código:
Analizando la función RegisterTemplateOverrides
La función RegisterTemplateOverrides se basa en el objeto interno TemplateManager._TemplateOverrides para mantener y guardar el estado de todas las personalizaciones de plantillas que se han hecho hasta el momento, por lo que lo primero que se hace es obtener ese objeto y luego pasárselo a la función _RegisterTemplatesInternal, como se puede observar en el código:
También vemos que se le pasa como parámetro un objeto llamado "renderCtx". Es un objeto de tipo RenderContext y está disponible en tiempo de ejecución para proveer algunas variables y mantener el estado del framework completo y que se pueda usar de forma consistente creando varios templates desde distintos ficheros JavaScript.
RenderContext Object
Este objeto es usado en casi todas las funciones de clienttemplates.js. Es un objeto dinámico compuesto de propiedades dinámicas. Propiedades que para cada función pueden ser distintas. En el caso concreto de la función RegisterTemplateOverrides las propiedades más importantes de este objeto son:
1var renderContext = {2
1 BaseViewID: /* ID en Schema.xml. Ver más en este post de Andrey */,2
1 ListTemplateType: /* List Template ID. Lista completa de template IDs */,2
1 ViewStyle: /* View Style: Boxed, no labels (12), Boxed(13),… */,2
1 OnPreRender: /* function or array of functions */,2
1 Templates: {2
1 View: /* function or string */,2
1 Body: /* function or string */,2
1 Header: /* function or string */,2
1 Footer: /* function or string */,2
1 Group: /* function or string */,2
1 Item: /* function or string */,2
1 Fields: {2
1 'Field1 Internal Name': {2
1 View: /* function or string */,2
1 EditForm: /* function or string */,2
1 DisplayForm: /* function or string */,2
1 NewForm: /* function or string */2
1 },2
1 'Field2 Internal Name': {2
1 View: /* function or string */,2
1 EditForm: /* function or string */,2
1 DisplayForm: /* function or string */,2
1 NewForm: /* function or string */2
1 },2
1 },2
1 },2
1 OnPostRender: /* function or array of functions */2
1};2
Es muy importante echarle un ojo despacio a estas propiedades para tener e incluso guardarse esta plantilla en favoritos de cara a poder reusarla luego cada vez que tengamos que definir una nueva plantilla de CSR.
Hasta ahora hemos echado un vistazo al código fuente que forma el Framework de los Templates, pero como realmente se conoce y aprende es depurando la aplicación y viendo qué valor van obteniendo cada una de las propiedades y variables con respecto al momento de ejecución.
A continuación, veremos un ejemplo en el que depuramos "hacemos debug" de esta función usando el debugger de Chrome (F12). En el ejemplo aplicaremos una personalización básica usando CSR a nivel de Item que aplique solamente a las listas Custom (100):
1SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {2
1 SPClientTemplates.TemplateManager.RegisterTemplateOverrides({2
1 Templates: {2
1 Item: function(ctx) {2
1 return String.format("Hi world");2
1 }2
1 },2
1 ListTemplateType: 1002
1});2
1})2
Depurando la función RegisterTemplateOverrides
A veces, lo más difícil cuando se quiere depurar un fichero de JavaScript en SharePoint (o cualquier web) es encontrar la línea donde poner el punto de interrupción. En este caso es doblemente difícil, porque el fichero clienttemplates.js de primeras no aparece en la pestaña Sources y de segundas el fichero está en su versión reducida.
Veamos como he conseguido poner ese punto de interrupción:
Abrimos el sitio de SharePoint y pulsamos F12 (en mi caso usando Chrome).
Vamos a la sección Network.
Veamos el ejemplo ahora realizado con un SharePoint OnPrem y con la depuración activada para que saque los ficheros .debug en lugar de los ficheros reducidos. Lo primero que comprueba la función RegisterTemplateOverrides es si le hemos pasado por parámetro el objeto renderContext con alguna personalización sobre algunos de los Templates, OnPreRender u OnPostRender. Si no es así, se sale de la función sin hacer nada, como es lógico.
Si por el contrario hemos configurado algún Template que aplicar, lo primero que se hace es obtener las Templates que ya han sido registradas hasta el momento usando la línea de código:
1var tempStruct = SPClientTemplates.TemplateManager._TemplateOverrides;2
La estructura del objeto mediante el cual se mantiene el estado de todas las personalizaciones o Templates es la siguiente:
Vemos como para cada ámbito o Template se almacena una sub-estructura de datos que contiene la siguiente forma:
Template Scope (Body, FIelds, Footer, Group, Header, Item y View) ViewStyle (default en este caso) ListTemplateType (109 in this case) BaseViewID (2 in this case) Nombre de la función
Para ver más información sobre:
Después se invoca a la función _RegisterTemplatesInternal que hace un merge entre las Templates aplicadas hasta el momento, obtenidas en el objeto anteriormente mostrado y las Templates pasadas como parámetro.
1SPClientTemplates.TemplateManager._RegisterTemplatesInternal = function(renderCtx, registeredOverrides) { … }2
Template pasada como parámetro: renderCtx:
Templates aplicadas hasta el momento:registeredOverrides:
Y después de hacer el merge:
Nótese como en la versión final del objeto que mantiene el estado "registeredOverrides" tenemos aplicadas dos personalizaciones distintas para Item, una para las listas de tipo 109 y otra para listas de tipo 100 (Custom List), y concretamente como en el código del ejemplo no especificamos BaseViewID, se asigna para todas usando el nombre "all".
Conclusiones
El objetivo de este artículo es conocer a fondo la tecnología Client-side rendering y JSLink de cara a poder saber qué tipo de personalizaciones podemos hacer y hasta donde podemos llegar. Me gustaría remarcar y compartir algunos aspectos descubiertos durante esta investigación:
Referencias
José Quinto @jquintozamora http://www.josharepoint.com