Thursday 5 October 2017

AngularJS to SharePoint 2013



CRUD operations on SharePoint list using AngularJS 


It is a simple implementation, where we are going to create a web part, which will have reference to a controller that will read, create, update and delete list items.

some prior experience with SharePoint and AngularJS. The environment is working upon is a SharePoint Online (Office 365) site.

created a Contacts list as in the below screenshot.


For this example,  will be using only 3 fields/columns in the list.
ID (Auto generated for every item in the list)
Last Name (Internal name: Title)
First Name (Internal name: FirstName)

Create the webpart

 added one Content Editor Webpart to a page and linked it to our view page [listItems.html].


The view page has 4 sections to view contacts, add, edit and delete them. For each of these operations, created 4 separate controllers. Below is the code for the same.


<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <script type="text/javascript" src="/sites/ListOps/Scripts/jquery.min.js"></script>
    <script type="text/javascript" src="/sites/ListOps/Scripts/angular.min.js"></script>
    <script type="text/javascript" src="/sites/ListOps/Scripts/listItems.controller.js"></script>
    
    <style type="text/css">
        .Table {
            display: table;
        }

        .Row {
            display: table-row;
        }

        .Cell {
            display: table-cell;
            padding: 5px;
        }
    </style>
</head>
<body>
    <h3>View Contacts</h3>
    <hr />
    <div ng-app="spApp">
        <div ng-controller="viewItemsController">
            <div ng-repeat="contact in contacts">
                {{contact.ID}}: {{contact.Title}}, {{contact.FirstName}}
                <br />
            </div>
        </div>
        <hr />


        <h3>Add Contacts</h3>
        <div ng-controller="addItemsController">
            <div class="Table">
                <div class="Row">
                    <div class="Cell">
                        First Name :
                    </div>
                    <div class="Cell">
                        <input type="text" id="firstName" ng-model="firstName" />
                    </div>
                </div>
                <div class="Row">
                    <div class="Cell">
                        Last Name :
                    </div>
                    <div class="Cell">
                        <input type="text" id="lastName" ng-model="lastName" />
                    </div>
                </div>
                <div class="Row">
                    <div class="Cell">
                        
                    </div>
                    <div class="Cell">
                        <input type="button" id="btnAddContact" value="Add Contact" ng-click="addContact()" />
                    </div>
                </div>
            </div>
        </div>
        <hr />


        <h3>Edit Contacts</h3>
        <div ng-controller="editItemsController">
            <div class="Table">
                <div class="Row">
                    <div class="Cell">
                        ID :
                    </div>
                    <div class="Cell">
                        <input type="text" id="itemId" ng-model="itemId" />
                    </div>
                </div>
                <div class="Row">
                    <div class="Cell">
                        First Name :
                    </div>
                    <div class="Cell">
                        <input type="text" id="firstName" ng-model="firstName" />
                    </div>
                </div>
                <div class="Row">
                    <div class="Cell">
                        Last Name :
                    </div>
                    <div class="Cell">
                        <input type="text" id="lastName" ng-model="lastName" />
                    </div>
                </div>
                <div class="Row">
                    <div class="Cell">

                    </div>
                    <div class="Cell">
                        <input type="button" id="btnEditContact" value="Edit Contact" ng-click="editContact()" />
                    </div>
                </div>
            </div>
        </div>
        <hr />


        <h3>Delete Contacts</h3>
        <div ng-controller="delItemsController">
            <div class="Table">
                <div class="Row">
                    <div class="Cell">
                        ID :
                    </div>
                    <div class="Cell">
                        <input type="text" id="itemId" ng-model="itemId" />
                    </div>
                </div>              
                <div class="Row">
                    <div class="Cell">

                    </div>
                    <div class="Cell">
                        <input type="button" id="btnDelContact" value="Delete Contact" ng-click="delContact()" />
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

In the head section,  made reference to the JQuery and the AngularJS libraries. And  also referred the controller script [listItems.controller.js]. also added some styling script for the webpart.

Controller Code

Below is the controller code. The controller name is according to the operation it performs.


var spApp = angular
                .module("spApp", [])
                .controller("viewItemsController", function ($scope, $http) {
                    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Contacts')/items?$select=Title,FirstName,ID";
                    $http(
                    {
                        method: "GET",
                        url: url,
                        headers: { "accept": "application/json;odata=verbose" }
                    }
                    ).success(function (data, status, headers, config) {
                        $scope.contacts = data.d.results;
                    }).error(function (data, status, headers, config) {
                    });
                    
                })

                .controller("addItemsController", function ($scope, $http) {
                    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Contacts')/items";
                    var vm = $scope;
                    vm.addContact = function () {
                        return $http({
                            headers: { "Accept": "application/json; odata=verbose", "X-RequestDigest": jQuery("#__REQUESTDIGEST").val() },
                            method: "POST",
                            url: url,
                            data: {
                                'Title': vm.lastName,
                                'FirstName': vm.firstName
                            }
                        })
                        .then(saveContact)
                        .catch(function (message) {
                            console.log("addContact() error: " + message);
                        });
                        function saveContact(data, status, headers, config) {
                            alert("Item Added Successfully");
                            return data.data.d;
                        }
                    }
                })

                .controller("editItemsController", function ($scope, $http) {
                    
                    var vm = $scope;                    
                    vm.editContact = function () {
                        var data = {
                            '__metadata': {
                                'type': 'SP.Data.ContactsListItem'
                            },
                            'Title': vm.lastName,
                            'FirstName': vm.firstName
                        };
                        return $http({
                            headers: {
                                "Accept": "application/json; odata=verbose",
                                "Content-Type": "application/json; odata=verbose",
                                "X-HTTP-Method": "MERGE",
                                "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
                                "Content-Length": data.length,
                                'IF-MATCH': "*"
                            },
                            method: "POST",
                            url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Contacts')/items(" + vm.itemId + ")",
                            data: data
                        })
                        .then(saveContact)
                        .catch(function (message) {
                            console.log("editContact() error: " + message);
                        });
                        function saveContact(data, status, headers, config) {
                            alert("Item Edited Successfully");
                            return data.data.d;
                        }
                    }
                })

                .controller("delItemsController", function ($scope, $http) {
                    
                    var vm = $scope;                    

                    vm.delContact = function () {
                        return $http({
                            headers: {
                                "X-HTTP-Method": "DELETE",
                                "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
                                'IF-MATCH': "*"
                            },
                            method: "POST",
                            url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Contacts')/items(" + vm.itemId + ")"
                        })
                        .then(saveContact)
                        .catch(function (message) {
                            console.log("delContact() error: " + message);
                        });
                        function saveContact(data, status, headers, config) {
                            alert("Item Deleted Successfully");
                            return data.data.d;
                        }
                    }
                });


Types of Crawl in SharePoint 2013



Disadvantage of the “Full Crawl” and “Incremental Crawl” as both can’t run in a parallel i.e. the content change during the crawl, it required next incremental crawl.
So what is new in continues crawl?
The content source that using continues crawl that run in parallel. The default waiting time is 15 min. So the default wait time can change via PowerShell , no UI for that. Now the content is up to date most of the time. This crawler only for SharePoint content source, so the job of the SharePoint administrator need to identify those content which are keep updating on the regular interval & also comes under the part of search need to be comes under “Continues crawl “category. The “Continuous Crawl” is a type of crawl that aims to maintain the index as current as possible. So the following are list of crawl are available in SharePoint 2013 search architecture.
  1. Run By User
    • Full Crawl
    • Incremental Crawl
    • Continues crawl
  2. Run By system (automated crawl)
    • Incremental Crawl (clean-up)
  1. Run by User: The content source created by user/Administrator and it is trigger/ scheduled by the user.
    • Full Crawl: 
      • Crawl full items
      • Can be scheduled
      • Can be stop and paused
      • When required
        • Change content access account
        • Added new manage properties
        • Content enrichment web service codes change/modified.
        • Add new IFilter
    • Incremental Crawl:
      • Crawl last modified content
      • Can be scheduled
      • Can be stop and paused
      • When required
      • Crawl last modified content
    • Continues Crawl
      • Index as current as possible.
      • Cannot be scheduled
      • Cannot be stop and paused (Once started, a “Continuous Crawl” can’t be paused or stopped, you can just disable it.)
      • When required
        • Content frequently changed (Multiple instance can be run in parallel).
        • Only for SharePoint Content Source
        • E-commerce site in crass site publishing mode.
  2. Run by System: The crawl run automatically by the timer job.
    • Clean-Up continues crawl (Microsoft definition): A continuous crawl does not process or retry items that return errors more than three times. A “clean-up” incremental crawl automatically runs every four hours for content sources that have continuous crawl enabled to re-crawl any items that repeatedly return errors. This incremental crawl will try to crawl the item again and then will postpone retries if the error persists.



  1. First of all, using PowerShell, logged in as the farm account (with admin access on the server and the farm of course) on a server in the farm, run the following commands:
    $setcba = Get-SPWebApplication "http://**********.com/"
    $setcba.UseClaimsAuthentication = 0;
    $setcba.Update()
  2. In the web.config of the web application, change the authentication section to reflect the following:
    • From:<authentication mode=”Forms” />
      <forms loginUrl=”/_login/default.aspx” />
      <authentication>
    • To:<authentication mode=”Windows” /
  3. Solution:
    • Change the “Claims Authentication Types” of Web Application from Kerberos to NTLM.
    • After cleaning the features, change the Claim Authentication type of Web Application from “Kerberos” to “NTLM”.
    • Steps: 1 Go to Central Admin è Application Management è Manage Web Applications è.
    • Steps: 2 Select the Web Application and click on “Authentication Providers” from ribbon.
    • Classic to Claim 1
      Steps: 3 Click on “Default” Zone.
      Classic to Claim 2
      Steps: 4 Change the “Claims Authentication Types” of Web Application from Negotiate (Kerberos) to NTLM.
      Classic to Claim 3