Abbiamo già parlato di paginazione tramite le REST API di SharePoint 2013 si, lo so. Ma se ricordate, vi avevo anche detto che ne avremmo riparlato, soprattutto per quanto riguarda la paginazione di elementi di lista.
Ne dobbiamo riparlare perché l'utilizzo dei parametri $skip e $top, che funzionano benissimo se facciamo una query REST su collezioni di oggetti come un insieme di siti, liste, file, campi, ecc..., purtroppo non funzionano se utilizziamo una collezione di elementi di lista come fonte di dati per la nostra query.
Provate a creare una nuova lista di contatti e riempirla con qualche elemento (direi almeno 5 o 6).

Paginare elementi di lista con le REST API di SharePoint 2013 - Parte 1

Fatto questo provate ad eseguire queste due query utilizzando il vostro browser (ovviamente inserendo la URL del vostro sito SharePoint e il nome della vostra lista di contatti):

  • http://siteurl/_api/lists/getByTitle(‘list name’)/items?$skip=0&$top=2
  • http://siteurl/_api/lists/getByTitle(‘list name’)/items?$skip=2&$top=2

Vi accorgerete che, nonostante abbiamo scritto la seconda query in modo tale da saltare i primi due elementi (utilizzando il parametro $skip=2), il risultato è lo stesso della prima query (cioè ritornano sempre i primi due elementi, nel nostro esempio "Uno" e "Due"). In pratica è come se il parametro $skip non venisse proprio considerato.
Se non ci credete, ecco le prove:

Paginare elementi di lista con le REST API di SharePoint 2013 - Parte 1

Paginare elementi di lista con le REST API di SharePoint 2013 - Parte 1

Io ho segnalato questo problema dai tempi della beta1 di SharePoint 2013, ma purtroppo non sono riuscito a far cambiar le cose. La risposta di Microsoft è sempre stata quella di utilizzare il campo "next" che è presente nella response quando si utilizza il parametro $top nelle nostra query REST.
Lo potete vedere anche dal browser.

Paginare elementi di lista con le REST API di SharePoint 2013 - Parte 1

Nel mio caso, il parametro "next" è valorizzato con la seguente URL:

http://sp2013/_api/lists/getByTitle('contacts')/items?$skiptoken=Paged=TRUE&p_ID=7&$skip=2&$top=2&$select=Title


Questa URL contiene i seguenti parametri:
  • $skiptoken, con valore Paged=TRUE
  • p_ID, con valore 7
  • più tutti i parametri originali della mia query iniziale (quindi $skip, $top e $select)

Il parametro $skiptoken indica a SharePoint che la query dovrà essere paginata, mentre il parametro p_ID indica l'identificativo dell'ultimo elemento della query corrente da cui dovrà partire l’elenco degli elementi per la prossima pagina di risultati.
La cosa divertente è che se proviamo a mettere questa URL in una nuova tab del browser, tornerà un errore 500. Questo perché per fare delle query paginate su elementi di lista sfruttando il parametro "next" della prima response, non è possibile utilizzare il parametro $skip.
Come vi dicevo, questo parametro non viene calcolato da SharePoint in questo caso e va quindi omesso.
Togliendo il parametro $skip dalla prima query e utilizzando la URL presente all'interno del parametro di ritorno "next", ecco che vediamo i risultati della seconda pagina.

Questa la URL che ho utilizzato:
http://sp2013/_api/lists/getByTitle('contacts')/items?$skiptoken=Paged=TRUE&p_ID=7&$top=2&$select=Title

Questi i risultati:

Paginare elementi di lista con le REST API di SharePoint 2013 - Parte 1

Ok, quindi un modo per paginare i risultati c’è.
Qual è il problema però?
Se ci pensate bene, ce ne sono un bel po’ di problemi...
Per prima cosa con questo meccanismo si pagina solo in avanti, il che significa che non posso implementare una paginazione con i numeri a piè pagina perché non avrei modo di dire a SharePoint di "farmi vedere i risultati della pagina X".
Poi non ho la minima idea dell'indice della pagina corrente, né le posso calcolare.
Cioè, lo potrei calcolare segnandomi il numero di pagina ad ogni nuova chiamata alle URL presenti all'interno del campo "next", ma purtroppo quel conteggio è concettualmente sbagliato in quanto non può tener presente di elementi che vengono aggiunti dopo le nostre richieste al server.

L'unica modalità di paginazione che posso implementare a causa di questo vincolo è una paginazione tipo la bacheca di Facebook che chiede al server sempre e solo i prossimi risultati.
Un bel buco insomma..

Perché c'è questo problema? Non lo so di preciso eh, ma posso farmi un po' di pensate a riguardo.
Mi sono accorto che questo è lo stesso meccanismo di paginazione che si può utilizzare per cercare di paginare i risultati di una query CAML tramite il Server Object Model di SharePoint.
Questa meccanismo si basa sulla classe SPListItemCollectionPosition, che per funzionare ha proprio bisogno di specificare i parametri "PAGED=TRUE" e "p_ID".
Vi invito a vedere questo esempio per farvi un'idea di quello di cui sto parlando:
http://blogs.msdn.com/b/dbadki/archive/2008/10/08/caml-query-execution-using-pagination-for-custom-columns.aspx

Quindi penso che il team di SharePoint aveva già questo problema nelle vecchie versioni del prodotto e che se l'è portato dietro anche in questo nuovo livello di API.
Purtroppo è veramente un peccato, perché le api REST introdotte da SharePoint 2013 sono uno strumento molto utile, ma hanno questo ed altri piccoli handicap.
Come vi dicevo, ho segnalato questo problema tramite il sito uservoice.com e potete anche voi contribuire a far arrivare la voce al team di sviluppo dando il vostro voto. Ecco l'indirizzo preciso:
http://officespdev.uservoice.com/forums/224641-general/suggestions/4606680-line-up-list-item-pagination-with-rest-api-using-

Nel prossimo post vedremo come possiamo implementare una paginazione di elementi di lista, sfruttando Javascript e KnockoutJs.