JS Link (Client Side Rendering) e la tecnologia che può essere usata in SharePoint 2013 e SharePoint Online per modificare il rendering di una lista lato client (il browser) tramite JavaScript.
Avevo già mostrato un esempio per modificare solo il rendering di un campo, ma è possibile andare oltre e modificare completamente l'aspetto di una lista.

Il modello oggetti lato client è il seguente:
var options = {
	Templates: {
		View: ..., // function or string
		Body: ..., // function or string
		Header: ..., // function or string
		Footer: ..., // function or string
		Group:  ..., // function or string
		Item:  ..., // function or string
		Fields: {
			'Field1 Internal Name': {
				View: ..., // function or string
				EditForm: ..., // function or string
				DisplayForm: ..., // function or string
				NewForm: ..., // function or string
			},
			'Field1 Internal Name': {
				View: ..., // function or string
				EditForm: ..., // function or string
				DisplayForm: ..., // function or string
				NewForm: ..., // function or string
			},
			// .... altri campi
		}
	},

	OnPreRender:  ..., // function or array of functions 
	OnPostRender:  ..., // function or array of functions 

	ListTemplateType: ..., // ID of the list template.
	ViewStyle: ...,  // ID of the view style 
	BaseViewID: ..., // BaseViewID of the list view.

};
questo oggetto contiene gli eventi che si possono sovrascrivere per modificare il render di ogni singola parte che compone la visualizzazione di una lista.
Gli eventi sono:
  • Templates.View: sovrascrive completamente tutto il render della lista
  • Templates.Body: sovrascrive il body della lista
  • Templates.Header: sovrascrive l'header della lista
  • Templates.Footer: sovrascrive il footer della lista
  • Templates.Group: sovrascrive l'intestazione del raggruppamento degli item della lista
  • Templates.Footer: sovrascrive l'item della lista
  • Templates.Fields: array che definisce come sovrascrivere lo specifico campo (SharePoint 2013 JSLink per cambiare la modalità con cui vengono visualizzati i campi)
Uno o più di questi eventi può essere sovrascritto con una stringa o una funzione JavaScript (oggetto Templates).
Ci sono anche degli eventi generali quali OnPreRender invocato prima di renderizzare qualsiasi elemento e OnPostRender invocato quando il DOM è stato creato (quindi si può accedere agli elementi della lista, ad esempio tramite jquery).
A questi si aggiungono delle proprietà che permetto di "agganciare" gli eventi ad una specifica lista:
  • ListTemplateType: l'id del template di lista
  • ViewStyle: l'id del template del tipo di visualizzazione della lista
  • BaseViewID: l'id del template di base della lista

Ad esempio per cambiare il render dell'intestazione (header) di una lista:
Area HeaderArea Header
si sovrascrive l'evento Header dell'oggetto Templates:
(function () {
  if (typeof SPClientTemplates === 'undefined') return;

  var options = {};
  options.Templates = {};
  options.Templates.Header = '<h2>Titolo lista: <#= ctx.ListTitle #></h2>';

  SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options);
  });

})();
e questo è il risultato:
Header sovrascrittoHeader sovrascritto
oppure con una funzione JavaScript:
(function () {
  if (typeof SPClientTemplates === 'undefined') return;

  function renderIHeader(ctx) {
    return '<h1>Nuovo titolo</h1>' + RenderHeaderTemplate(ctx);
  }

  var options = {};
  options.Templates = {};
  options.Templates.Header = renderIHeader;

  SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options);
  });

})();
in questo caso ho mantenuto anche l'header originale tramite la funzione RenderHeaderTemplate:
Header sovrascritto con funzioneHeader sovrascritto con funzione
Il codice JavaScript può essere inserito all'interno della pagina tramite una Script Editor Web Part oppure salvato in una document library (es. Style Library) e linkato alla Web Part della lista tramite la proprietà Collegamento JS:
web part property js linkweb part property js link

Un altro esempio è quello di modificare completamente il rendering del body della web part mantenendo la paginazione (Footer);
(function () {
  if (typeof SPClientTemplates === 'undefined') return;

  function renderBody(ctx) {
    var s = '<div class="sgart-news">';
    var data = ctx.ListData.Row;  // le righe correnti della vista
    for (var i = 0; i < data.length; i++) {
      var item = data[i];
      var classCheckedOut = item.CheckedOutUserId != 0 ? ' unpublished' : '';
      var imgSrc = sgart.getImageSrc(item.PublishingRollupImage, item.PublishingPageImage);
      var dateStr = sgart.formatDateString(item.ArticleStartDate, true);

      s += String.format('<div class="row article{5}">'
        + '<div class="col-md-4 col-sx-12">'
        + ' <div class="bw"><a href="{0}"><img class="img-responsive" alt="" src="{1}?RenditionID=5"></a></div>'
        + '</div>'
        + '<div class="col-md-8 col-sx-12">'
        + ' <div class="date">{2}</div>'
        + ' <div class="title"><a title="" href={0}">{3}</a></div>'
        + ' <div class="description">{4}</div>'
        + '</div></div>', item.FileRef, imgSrc, dateStr, item.Title, item.Comments, classCheckedOut);
    }
    s += '</div>';
    return s;
  };

  var options = {};
  options.Templates = {};
  options.Templates.Header = '&#160;';  // se voglio nascondere l'header non posso lasciare una stringa vuota o un valore null
  options.Templates.Body = renderBody;  // sovrascrivo il body

  SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options);
  });

})();
questo esempio si basa su alcune funzioni comuni:
var sgart= sgart|| {};
sgart.mesi = ['', 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giungo', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'];
sgart.mesiShort = ['', 'Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'];

sgart.getImageSrc = function (rollupImage, pageImage) {  // se non c'è la rollup (rollupImage) ritorno l'immagine principale (pageImage)
  var reSrc = /src=\"(.+?)\"/gi;
  var str = rollupImage; //"<div dir="" class="ms-rtestate-field"></div>"
  var imgSrc = null;
  if (typeof str !== 'undefined' && str !== null) {
    var re = str.match(reSrc);
    if (re !== null && re.length > 0)
      imgSrc = re[0];
  }
  if (imgSrc === null) {
    var str = pageImage  //"<div dir="" class="ms-rtestate-field"><img alt="" src="/News/PublishingImages/nomefile.JPG" style="BORDER&#58;0px solid;" /></div>"
    if (typeof str !== 'undefined' && str !== null) {
      var re = str.match(reSrc);
      if (re !== null && re.length > 0)
        imgSrc = re[0];
    }
  }
  if (imgSrc !== null) {
    imgSrc = imgSrc.substring(5);
    var i = imgSrc.indexOf('?');
    if (i !== -1)
      imgSrc = imgSrc.substring(0, i);
  }
  return imgSrc;
};

sgart.formatDateString = function (str, toLower) {  //input: 16/03/2017
  if (str === null || str === '') return '';
  var d = str.substr(0, 2);
  var m = parseInt(str.substr(3, 2));
  var y = str.substr(6, 4);

  var mese = sgart.mesiShort[m];
  if (typeof toLower === 'boolean' && toLower === true)
    return d + ' ' + mese.toLowerCase() + ' ' + y;
  else
    return d + ' ' + mese + ' ' + y;
};
Attenzione perchè l'esempio riportato funzioni è necessario che la vista contenga i campi utilizzati come: Title, PublishingRollupImage, PublishingPageImage, ecc..
Utilizzare sempre la funzione SP.SOD.executeFunc per registrare gli script in modo da essere sicuri che la libreria clienttemplates.js sia caricata
Con questo script è possibile vedere in console del browser (F12) la sequenza con cui vengono richiamati i singoli eventi:
(function () {
  if (typeof SPClientTemplates === 'undefined') return;

  function log(title, ctx){
    console.log(title);
    //console.log(ctx);
  }

  function renderView(ctx){
    log('View',ctx);
    return RenderListView(ctx);
  }

  function renderBody(ctx){
    log('Body rows: ' + ctx.ListData.Row.length, ctx);
    return RenderBodyTemplate(ctx);
  }

  function renderHeader(ctx){
    log('Header ListTitle: ' + ctx.ListTitle, ctx);
    log(' - ListTemplateType: ' + ctx.ListTemplateType, ctx);
    //log(' - ViewStyle: ' + ctx.ViewStyle, ctx);
    log(' - BaseViewID: ' + ctx.BaseViewID, ctx);
    return RenderHeaderTemplate(ctx);
  }
	
  function renderFooter(ctx){
    log('Footer first row: ' + ctx.ListData.FirstRow, ctx);
    return RenderFooterTemplate(ctx);
  }

  function renderGroup(ctx){
    log('Group id: ' + ctx.CurrentItem.ID, ctx);
    return RenderGroupTemplate(ctx);
  }

  function renderItem(ctx){
    log('Item id: ' + ctx.CurrentItem.ID, ctx);
    return RenderItemTemplate(ctx);
  }

  function renderItem(ctx){
    log('Item id: ' + ctx.CurrentItem.ID, ctx);
    return RenderItemTemplate(ctx);
  }
	
  function onPreRender(ctx){
    log('OnPreRender', ctx);
    //ctx.ListTitle = prompt('Inserisci il titolo della lista', ctx.ListTitle);
    //log('OnPreRender new title: ' + ctx.ListTitle, ctx);
  }

  function onPostRender(ctx){
    log('OnPostRender', ctx);
  }
	
  var options = {};
  options.Templates = {};
  //options.Templates.View = renderView;
  options.Templates.Body = renderBody;
  options.Templates.Header = renderHeader;
  options.Templates.Footer = renderFooter;
  options.Templates.Group = renderGroup;
  options.Templates.Item = renderItem;

  options.OnPreRender = onPreRender;
  options.OnPostRender = onPostRender;
	
  SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function () {
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options);
  });
 
})();
il risultato simile a questo:
OnPreRender
Header ListTitle: Pagine
 - ListTemplateType: 850
 - BaseViewID: 1
Body rows: 3
Item id: 3
Item id: 36
Item id: 7
Footer first row: 1
OnPostRender

Vedi anche SharePoint 2013 : An Introduction to JSLink è Client-side rendering (JS Link) code samples