CRUD operation with Dialog box using REST in SharePoint Hosted App


The REST API in SharePoint 2013 provides developers with a simple standardized method of accessing information contained within SharePoint.
REST is a software architecture that uses uniform resource identifiers (URI) to specify operations against a remote service. Open Data Protocol (OData) is the protocol that is used along with REST to access many cloud-based services.
REST-based (known more commonly as “RESTful”) solutions use standard HTTP GET, POST, PUT, and DELETE verbs to perform CRUD operations against a remote source. Support for the standard HTTP verbs provides easy cross-platform data access and is ideally suited for cloud-based apps. The OData protocol returns results in either the Atom Publishing Protocol (AtomPub) or JSON.

 

Obtaining the site URI

One key prerequisite to interacting with SharePoint lists items is to obtain the correct URI for the SharePoint site the list is hosted in. There are multiple ways to do this:
  1. On SharePoint pages _spPageContextInfo.siteAbsoluteUrl contains the URI to the site that the app is installed within (the parent site).
  2. You can include a set of standard tokens in the URL attribute of both pages and web parts. Adding {StandardTokens} will include the following 7 parameters to the url; SPHostUrl, SPHostTitle, SPAppWebUrl, SPLanguage, SPClientTag, SPProductNumber, and SenderId. These will need to be split out of the URL to be used. There are multiple ways to do this. The simplest is to loop through all the parameters until you find the parameter you are looking for. The following snippet of code searches for the SPAppWebUrl.

Fig1.1

List Item Types

To update or create list items you will need to include the list item type. This is a string automatically created by SharePoint when the list is first created. Two possible ways to obtain this are:
  1. Perform a read operation on the list and locate the type within the returned set of elements. In JSON format the type can be found within the __metadata attribute of all of the returned list items. In Atom/xml format (the default format returned if you query from a web browser) you can find it in the category scheme attribute (labelled ‘term’) within the item.
  2. You can attempt to generate the value from the list name. In general list item types follow the convention SP.Data.ListNameListItem (e.g. list name is “Test”, list item type is SP.Data.TestListItem). However this is not always the case. For example SharePoint automatically capitalises the first letter of the list name (e.g. list name “test” list item type is SP.Data.TestListItem). The following code snippet shows how to generate the List Item Type based on the list name.

Request Digests

A replay attack occurs when a valid request is sent to the server and a copy of that request is stored. The request is then sent multiple times (replayed). This can result in a variety of different issues the most common of which is duplication of data. To prevent this, SharePoint requires the user to include a request digest value with each create, update and delete operation. This value is then used by SharePoint to identify non-genuine requests. Inside SharePoint Hosted apps, the request digest can be found by reading the value of the “__REQUESTDIGEST” object within the html page.
1.      var digestValue = $("#__REQUESTDIGEST").val()
Note: this will only work on pages that contain the SharePoint Chrome element. The example above requires JQuery to work.

eTags

When updating or deleting items within SharePoint lists via REST you must specify the Entity Tag (eTag) value that was returned with the item during the initial query. This enables SharePoint to determine if the item has changed since it was requested. Alternatively you can tell SharePoint to perform the operation regardless by specifying * as the eTag value. For example:
  1. “If-Match”: item.__metadata.etag can be used to specify the actual eTag value (‘item’ is the object returned from SharePoint containing the list item in JSON format).
  2. “If-Match”: “*” can be used to match any eTag value resulting in the operation being performed regardless of the actual value.



Create SharePoint Hosted App with below mention structure


Fig 1.2

Add Default data to Custom Customers List

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ListInstance Title="Customers" OnQuickLaunch="TRUE" TemplateType="10000"
                Url="Lists/Customers" Description="My List Instance">
    <Data>
      <Rows>
        <Row>
          <Field Name="FirstName">Scot</Field>
          <Field Name="Title">Hillier</Field>
        </Row>
        <Row>
          <Field Name="FirstName">Ted</Field>
          <Field Name="Title">Pattison</Field>
        </Row>
        <Row>
          <Field Name="FirstName">Mike</Field>
          <Field Name="Title">Morton</Field>
        </Row>
      </Rows>
    </Data>
  </ListInstance>
</Elements>

Add HTML Content to Default.aspx

<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <script type="text/javascript" src="../Scripts/jquery-1.6.2.min.js"></script>
    <script type="text/javascript" src="/_layouts/15/sp.runtime.debug.js"></script>
    <script type="text/javascript" src="/_layouts/15/sp.debug.js"></script>
    <script type="text/javascript" src="../Scripts/jsrender.js"></script>
    <!-- Add your CSS styles to the following file -->
    <link rel="Stylesheet" type="text/css" href="../Content/App.css" />

    <!-- Add your JavaScript to the following file -->
    <script type="text/javascript" src="../Scripts/App.js"></script>
    <script type="text/javascript" src="../Scripts/jquery-ui-1.9.2.min.js"></script>

</asp:Content>

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <h1>SharePoint Hosted App -CRUD Operations using REST </h1>
    <div id="toolbar">
        <input type="button" id="cmdAddNewCustomer" value="Add New Customer" class="ms-ButtonHeightWidth" />
    </div>
    <div id="results"></div>
    <div id="viewCustomerDialog" style="display: none;"></div>
    <div id="editCustomerDialog" style="display: none;">
        <table id="customerEditTable">
            <tr>
                <td>First Name:</td>
                <td><input id="customerFirstName" /></td>
            </tr>
            <tr>
                <td>Last Name:</td>
                <td><input id="customerLastName" /></td>
            </tr>
        </table>
        <div style="display: none;">
            <input id="customerId" />
            <input id="customerETag" />
        </div>
    </div>
</asp:Content

Read Item from Customer List (Code in App.js file)
A simple ajax call is executed against the SharePoint server. If the call succeeds then the success function (passed in as a parameter) is called, if it fails then the failure function (also passed in as a parameter) is called. In both cases the data returned from the server is passed through to the function.

function Read() {
    var url = _spPageContextInfo.webServerRelativeUrl
    getListItems(url, function (data) {
        var odataResults = data.d.results;

        // set rendering template
        var tableHeader = "<thead>" +
                          "<td>Last Name</td>" +
                          "<td>First Name</td>" +
                          "<td>&nbsp;</td>" +
                          "<td>&nbsp;</td>" +
                        "</thead>";

        var table = $("<table>", { id: "customersTable" }).append($(tableHeader));

        var renderingTemplate = "<tr>" +
                                  "<td>{{>Title}}</td>" +
                                  "<td>{{>FirstName}}</td>" +
                                  "<td><a href='javascript: onUpdateCustomer({{>Id}});'><img src='../Content/EDITITEM.gif' alt='Edit' /></a></td>" +
                                  "<td><a href='javascript: onDeleteCustomer({{>Id}});'><img src='../Content/DELITEM.gif' alt='Delete' /></a></td>" +
                                "</tr>";


        $.templates({ "tmplTable": renderingTemplate });
        table.append($.render.tmplTable(odataResults));
        $("#results").append(table);


    }, function (data) {
        alert("Ooops, an error occured. Please try again");
    });
}

function getListItems(siteurl, success, failure) {
    $.ajax({
        url: siteurl + "/_api/web/lists/getbytitle('Customers')/items?$select=Id,FirstName,Title" + "&$orderby=Title,FirstName",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {
            success(data);
        },
        error: function (data) {
            failure(data);
        }
    });
}



Update

In contrast to reading list items updating them is probably the hardest operation. To update an item you will need to obtain the URL of the item and, depending on your handling of eTags, the eTag value. The simplest way to do this is to perform a get operation and then use the properties of the item. The update method uses the same method mentioned for update operations to generate the list item type. Read Function assign Id to all Edit Button, On Click of Edit button , Dialog Open with existing value of corresponding Id , User can update the existing value and Click on Save. Once User click on the save button, It will update the base page data without refreshing the page.

function onUpdateCustomer(customerId) {

    var url = _spPageContextInfo.webServerRelativeUrl;
    updateListItem(customerId, url, function () {
        alert("Item updated, refreshing avilable items");
    }, function () {
        alert("Ooops, an error occured. Please try again");
    });
}

// Update Operation
function updateListItem(itemId, siteUrl, success, failure) {

    $.ajax({
        url: siteUrl + "/_api/web/lists/getByTitle('Customers')/items(" + itemId + ")",
        method: "Get",
        headers: { "ACCEPT": "application/json;odata=verbose" },
        success: onCustomerReturned,
        error:function (data) {
            failure(data);
        }

    });
}



function onCustomerReturned(data) {

    $("#customerId").val(data.d.Id);
    $("#customerLastName").val(data.d.Title);
    $("#customerFirstName").val(data.d.FirstName);
    $("#customerETag").val(data.d.__metadata.etag);

    var customer_dialog = $("#editCustomerDialog");
    customer_dialog.dialog({
        autoOpen: true,
        title: "Edit Customer",
        width: 420,
        buttons: {
            "Save": updateCustomer,
            "Cancel": function () { $(this).dialog("close"); },
        }
    });

}

function updateCustomer(event) {

    $(this).dialog("close");

    var Id = $("#customerId").val();
    var FirstName = $("#customerLastName").val();
    var LastName = $("#customerFirstName").val();
    var etag = $("#customerETag").val();
    $.ajax({
        url: _spPageContextInfo.webServerRelativeUrl + "/_api/web/lists/getByTitle('Customers')/getItemByStringId('" + Id + "')",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(
        {
            '__metadata': {
                'type': 'SP.Data.CustomersListItem'
            },
            'Title': LastName,
            'FirstName': FirstName

        }),
        headers: {
            "accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val(),
            "IF-MATCH": "*",
            "X-Http-Method": "PATCH"
        },
        success: function (data) {
            Read();
        },
        error: function (err) {
            alert(JSON.stringify(err));
        }
    });
}


Delete

The code below performs a delete operation. In a similar way to updating items delete operations are performed using the URI of the item


// occurs when a user clicks the delete button
function onDeleteCustomer(customerId) {

    var url = _spPageContextInfo.webServerRelativeUrl;
    deleteListItem(customerId, url, function () {
        alert("Item deleted, refreshing avilable items");
        Read();
    }, function () {
        alert("Ooops, an error occured. Please try again");
    });
}

// Delete Operation
function deleteListItem(itemId, siteUrl, success, failure) {
  
        $.ajax({

            url: siteUrl + "/_api/web/lists/getByTitle('Customers')/getItemByStringId('" + itemId + "')",
            type: "DELETE",
            headers: {
                "accept": "application/json;odata=verbose",
                "X-RequestDigest": $("#__REQUESTDIGEST").val(),
                "IF-MATCH": "*"
            },
            success: function (data) {
                success(data);
            },
            error: function (data) {
                failure(data);
            }
        });
    }






Create
First bind the OnAddCustomer event to input button
On click Button , Div based dialog box will appear as pop up
User can enter first name and last name and click on Save, Parent table data will be refresh by new record.

$(function () {

    $("#cmdAddNewCustomer").click(onAddCustomer);
    $("#cmdAddNewCustomer").button();
    $("#results").append($("<img>", { src: "../Content/gears_anv4.gif" }));
    Read();
});


function onAddCustomer(event) {

    var customer_dialog = $("#editCustomerDialog");
    customer_dialog.dialog({
        autoOpen: true,
        title: "Add New Customer",
        width: 420,
        buttons: {
            "Save": saveNewCustomer,
            "Cancel": function () { $(this).dialog("close"); },
        }
    });

}

function saveNewCustomer(event) {

    $(this).dialog("close");
    // clear results and add spinning gears icon
    $("#results").empty();
    $("<img>", { "src": "../Content/GEARS_AN.GIF" }).appendTo("#results");

    // get data from dialog for new customer
    var LastName = $("#customerLastName").val();
    var FirstName = $("#customerFirstName").val();

    $.ajax({
        url: _spPageContextInfo.webServerRelativeUrl +"/_api/web/lists/getByTitle('Customers')/items",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(
        {
            '__metadata': {
                'type': 'SP.Data.CustomersListItem'
            },
            'Title': LastName,
            'FirstName': FirstName,
        }),
        headers: {
            "accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function () {
            Read();
        },
        error: function (err) {
            alert(JSON.stringify(err));
        }
    });
}




Out Put:-

No comments:

Post a Comment