Questo articolo è il terzo di una mini-serie di articoli sull'interfaccia REST di SharePoint 2013 e KnockoutJs:


Negli ultimi due post, abbiamo visto come sfruttare KnockoutJs e la nuova interfaccia REST di SharePoint 2013 per leggere i dati di una lista e cancellarne alcuni.
Oggi vedremo come fare un inserimento di un nuovo elemento.

Partiamo dalla parte JavaScript.
Per prima cosa dobbiamo definire la struttura dell’oggetto che vogliamo passare al server e che verrà poi inserito all'interno di una lista SharePoint. Per definire questa struttura dobbiamo utilizzare il "Constructor pattern" di JavaScript, in questo modo:

window.D4S.SP2013.Contact = function () {

var self = this;
self.Id = ko.observable(0);
self.Title = ko.observable('');
self.FirstName = ko.observable('');
self.Email = ko.observable('');
self.__metadata = { 'type': 'SP.Data.ContactsListItem' };
};

Questo oggetto JavaScript ci serve per avere a disposizione tutte le proprietà che rappresentano il nostro dato all'interno di SharePoint, rappresentate come degli observable.
Le cose su cui dovete fare assolutamente attenzione sono due:
  • I nomi delle proprietà devono essere uguali agli InternalName dei campi della vostra lista SharePoint
  • Ci deve essere una proprietà chiamata "__metadata" (con il doppio underscore) valorizzata con il tipo di elemento SharePoint che vogliamo inserire.
Il tipo di elemento è una stringa che dice a SharePoint come deserializzare il dato che gli stiamo passando e validare se la lista che abbiamo scelto per l'inserimento può contenere un elemento con tale struttura.
Per recuperare questa stringa, basta fare una richiesta alla URL:

/_api/web/lists/getByTitle('vostra lista')/items


In ogni nodo di tipo "entry" (che rappresenta un singolo item della nostra lista), c’è un elemento di tipo "category" che contiene esattamente la stringa che ci serve:

<category term="SP.Data.ContactsListItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />


Questa stringa è sempre composta dal nome della lista + "ListItem".
In generale comunque, l'oggetto che dovete preparare da passare poi al servizio di inserimento, dovrà avere la medesima struttura dell'oggetto osservabile che abbiamo creato durante l'operazione di lettura tramite il metodo "ko.mapping.fromJS" (vedi il post sulla lettura).

Fatto questo, dobbiamo creare all'interno del nostro view model una proprietà osservabile d'appoggio che utilizzeremo per contenere sia i dati da inserire che eventuali dati da modificare (ma questo lo vedremo nel prossimo post). Questa proprietà, alla prima inizializzazione, dovrà contenere una nuova istanza dell'oggetto D4S.SP2013.Contact.

window.D4S.SP2013.CrudSampleViewModel = function (digest) {

var self = this;
self.currentContact = ko.observable(new D4S.SP2013.Contact());

//etc.. }

Perchè questa variabile d'appoggio? Lo vedremo al momento della creazione della view, non preoccupatevi.

Bene, pensiamo ora come se questa variabile d'appoggio fosse valorizzata con i dati di un nuovo contatto da inserire all'interno della nostra lista SharePoint. Questa operazione di popolamento delle varie proprietà, verrà fatta in automatico da KnockoutJs che lega le proprietà osservabile del nostro oggetto d'appoggio al valore di campi di input presenti nella view.
Così facendo, possiamo fare la nostra richiesta HTTP (sempre in POST), e passare come dati della nostra richiesta il nostro oggetto d'appoggio opportunamente convertito in sintassi JSON pura (sfruttando il metodo di KnockoutJs "ko.mapping.toJSON").

self.insert = function () {

$.ajax({
url: self.webUrl.SPItemsFromList('Contacts'),
type: 'POST',
data: ko.mapping.toJSON(self.currentContact()),
contentType: self.requestContentType,
headers: {
'content-type': self.requestContentType,
'Accept': self.requestContentType,
'X-RequestDigest': self.digest
},
success: function (data) {
self.currentContact(new D4S.SP2013.Contact());
self.read();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(errorThrown);
}
});
};

Per fare un'inserimento sfruttando le API REST di SharePoint 2013, dobbiamo creare una richiesta HTTP che segua queste regole:
  • La chiamata deve essere fatta alla URL che rappresenta la collezione di elementi in cui vogliamo inserire il nostro nuovo elemento (questa è una regola d'oro per l'utilizzo dell’interfaccia REST di SharePoint 2013):
    • /_api/web/lists/getByTitle('Contacts')/items
  • La chiamata deve essere fatta in POST
  • Tra gli header della chiamata, dobbiamo passare:
  • Passare come contenuto della richiesta, l’oggetto che vogliamo inserire nella lista SharePoint
Rispetto alla cancellazione, non è necessario passare tra gli header un valore per l'header X-HTTP-Method, in quanto l'operazione di inserimento è l'operazione di default.

Ok, ora che abbiamo visto tutto il codice di scripting utile a definire la struttura dei nostri dati e la chiamata alle API REST di SharePoint 2013, vediamo come scrivere la view e popolare questi dati.
Come vi dicevo, gira tutto intorno all'oggetto d’appoggio che abbiamo inserito all'interno della variabile "currentContact".

window.D4S.SP2013.CrudSampleViewModel = function (digest) {

var self = this;
self.currentContact = ko.observable(new D4S.SP2013.Contact());

//etc.. }

All'interno della view il nostro compito è quello di legare le proprietà osservabili dell'oggetto contenuto in questa variabile d'appoggio. Per farlo, sfruttiamo la potenza dell'engine di templating di KnockoutJs.
Nel punto della pagina in cui vogliamo inserire il nostro form di inserimento, sfruttiamo il binding "template" in questo modo:

<div data-bind="template: { name: 'NewEditTemplate', data: currentContact }"></div>


Specifando:
  • Il nome del template da utilizzare per il rendering
  • La fonte dati che verrà utilizzata come nuovo binding context da KnockoutJs
Così facendo, possiamo passare alla definizione del template e dei binding alle varie proprietà del nostro oggetto Contact.

<script id="NewEditTemplate" type="text/html">

<div>
<input type="text" data-bind="value: Title" placeholder="Insert last name ..." style="width: 200px" />
</div>
<div>
<input type="text" data-bind="value: FirstName" placeholder="Insert first name ..." style="width: 200px" />
</div>
<div>
<input type="text" data-bind="value: Email" placeholder="Insert e-mail address ..." style="width: 200px" />
</div>
<button data-bind="click: $root.insert">Save</button>
</script>

Se fate caso, in questo pezzo di view, è cambiato il contesto di binding. Il che ci permette di legare dei controlli input alle proprietà del nostro oggetto d’appoggio in questo modo:

value: FirstName


Se non cambiamo il binding context attraverso l'uso del template la pagina sarebbe andata in errore, in quanto il view model legato alla view è ancora il view model iniziale, che però non contiene una variabile di tipo "FirstName" (per esempio).
Cambiando il contesto invece, possiamo accedere direttamente alle proprietà del nuovo contesto di binding rappresentato dalla nostra variabile d'appoggio.
Per tornare invece al view model "padre" e, per esempio, richiamare una delle sue funzioni (nel nostro caso la funzione di inserimento, da richiamare al click sul pulsante "Save") KnockoutJs ci mette a disposizione una particolare variabile, la variabile $root.
Questa variabile rappresenta il view model principale della nostra view, cioè quell'oggetto che abbiamo legato alla view tramite il metodo "ko.applyBindings" (riandate al primo post di questa mini-serie).

$(document).ready(function () {

var model = new D4S.SP2013.CrudSampleViewModel($("#__REQUESTDIGEST").val());
ko.applyBindings(model);
});

Così facendo KnockoutJs popolerà per noi il nostro oggetto d'appoggio, inserendo in automatico il testo che l'utente specifica all'interno dei vari campi di input, così da darci la possibilità di serializzarlo in JSON e mandarlo al server tramite la chiamata REST che abbiamo descritto poco sopra.

Ecco conclusa la procedura di inserimento.
Se volete fare i fighi poi, potete gestire un loader, dare un messaggio all'utente in caso di successo o di errore, ecc... ;)

Vi ricordo che potete vedere l'esempio in funzione scaricando il progetto d'esempio che ho creato:
- D4S.SP2013.FrontEndCRUD.zip (1.8 MB)