Using WebApi example - spreadsheet
IMPORTANT
Help UKRAINE
! Your action matters! Donate
to support Ukrainian Army! Donate to charity funds!
Organize/join street protests in your city to support Ukraine and condemn Russian aggression!
Expose and report Russian disinformation! #StandWithUkraine
Help UKRAINE
! Your action matters! Donate
to support Ukrainian Army! Donate to charity funds!
Organize/join street protests in your city to support Ukraine and condemn Russian aggression!
Expose and report Russian disinformation! #StandWithUkraine Some time ago, in my previous post about Web API I mentioned the example of its usage - creating Excel-like experience on the Portal. The time has come to show that example. In my code, I am using a third-party library called jExcel. Below you can find a video of how it looks like and sample code. The code may not reveal the best practices for jExcel library and provided only as a reference.
IMPORTANT
As the date of the article Web API is still in Preview and is not suitable for the production environment.
<script src="https://bossanova.uk/jexcel/v4/jexcel.js"></script>
<link rel="stylesheet" href="https://bossanova.uk/jexcel/v4/jexcel.css" type="text/css" />
<script src="https://bossanova.uk/jsuites/v2/jsuites.js"></script>
<link rel="stylesheet" href="https://bossanova.uk/jsuites/v2/jsuites.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Material+Icons" />
<div class="container">
<h1>Sample spreadsheet</h1>
<div id="spreadsheet"></div>
</div>
<!-- Fetching list of contacts -->
{% fetchxml contactList %}
<fetch version="1.0" mapping="logical">
<entity name="contact">
<attribute name="firstname"></attribute>
<attribute name="lastname"></attribute>
<attribute name="emailaddress1"></attribute>
<attribute name="telephone1"></attribute>
<attribute name="contactid"></attribute>
<filter type="and">
<condition attribute="fullname" operator="like" value="%(sample)%" />
</filter>
</entity>
</fetch>
{% endfetchxml %}
<script>
//Web API ajax wrapper
(function (webapi, $) {
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();
shell.getTokenDeferred().done(function (token) {
// Add headers for ajax
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
"__RequestVerificationToken": token
}
});
} else {
ajaxOptions.headers["__RequestVerificationToken"] = token;
}
$.ajax(ajaxOptions)
.done(function (data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject); //ajax
}).fail(function () {
deferredAjax.rejectWith(this, arguments); // On token failure pass the token ajax and args
});
return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)
function saveContact(contactFieldsArr) {
let contactObj = {
"firstname": contactFieldsArr[0],
"lastname": contactFieldsArr[1],
"emailaddress1": contactFieldsArr[2],
"telephone1": contactFieldsArr[3],
}
let requestURL = `/_api/contacts(${contactFieldsArr[4]})`;
webapi.safeAjax({
type: "PATCH",
url: requestURL,
contentType: "application/json",
data: JSON.stringify(contactObj),
success: function (res) {
console.log(res);
}
});
}
function saveContacts() {
for (let index = 0; index < changedRows.length; index++) {
const rowIndex = changedRows[index];
let rowData = table.getRowData(rowIndex);
saveContact(rowData);
}
}
// list of row indexes that were changed
var changedRows = [];
// function that will be called when data is changed in table
var onDataChange = function(instance, cell, colNum, rowNum, value) {
let findIndex = changedRows.findIndex(elem => elem == rowNum);
if(findIndex == -1) {
changedRows.push(rowNum);
}
}
var data = [
{% for entity in contactList.results.entities %}
[
"{{ entity.firstname }}",
"{{ entity.lastname }}",
"{{ entity.emailaddress1 }}",
"{{ entity.telephone1 }}",
"{{entity.contactid}}",
] {% unless forloop.last %}, {% endunless %}
{% endfor %}
];
var table = jexcel(document.getElementById('spreadsheet'), {
data: data,
columns: [{
type: 'text',
title: 'First Name',
width: 220
},
{
type: 'text',
title: 'Last Name',
width: 220
},
{
type: 'text',
title: 'Email',
width: 220
},
{
type: 'text',
title: 'Phone',
width: 150
},
{
type: 'text',
title: 'Id',
width: 120,
readOnly: true
}
],
toolbar: [{
type: 'i',
content: 'undo',
onclick: function () {
table.undo();
}
},
{
type: 'i',
content: 'redo',
onclick: function () {
table.redo();
}
},
{
type: 'i',
content: 'save',
onclick: function () {
saveContacts();
}
}
],
onchange: onDataChange
});
</script>