CRUD operations on SharePoint list using AngularJS

In this post, I am going to share some code snippets for performing CRUD operation on a SharePoint list using only client side script written with AngularJS.

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

I hope you are reading this post with some prior experience with SharePoint and AngularJS. The environment I am working upon is a SharePoint Online (Office 365) site.

I have created a Contacts list as in the below screenshot.


For this example, I 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

I have 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, I have 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, I have made reference to the JQuery and the AngularJS libraries. And I have also referred the controller script [listItems.controller.js]. I have 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;
                        }
                    }
                });

Hope this post is helpful for folks working purely on client side scripting with SharePoint in Office 365.

Blessed with 1080p 60fps gaming rig

Honestly, nothing beats the satisfaction playing your favorite games, on a new rig, at 1080p 60fps.

The 1080p resolution is pretty standard in 2015, and has been sticking around for some time now. But the power and efficiency of new GPUs has increased exponentially. Now a days anyone can get a great gaming experience without breaking the bank.

I bought my first PC back in 2005, mostly built using cheap parts available in market. I was in college and budget was really an issue, especially in India, where you actually buy a PC to learn "coding" :P

It was not much, but did the job. Used to become hot like hell. Could dry my cloths during rainy days. Had two hard drives, both of them failed after 2 years of use, due to a bad power supply unit.

Later on I got a job, and I was moving from place to place, decided that a laptop will suffice my gaming crave. Spent 40K INR (~$600) on an Acer Aspire 5738G, with Core 2 Duo processor, 4GB memory and Ati Radeon 4570HD graphics card.

Nonetheless, it was not capable of pulling decent frame rates at 768p (its native resolution). So I spent lot of time tinkering and tweaking the settings, which at last lead to a lot of frustration.

So it was decided, no laptops, period. I will build a PC with a great multi-core processor, great GPU, high quality parts, bang for bucks, that will gobble up any game you throw at it. Also it should be quiet and energy efficient.

So here is the list.

Processor - AMD FX-6300 Black Edition


A very good 6 core processor that is overclockable. Can't compare with Core i5 Haswell's brute force, but don't want any more at this price.
Core i3 is hyper-threaded dual core, but more core is better. A lot of games now demand 4 core processors.

Motherboard - Asus M5A97 LE R2.0


Asus makes quality motherboard. This is a 970 chipset motherboard with overclocking capabilities, 6Gbps (SATA 3) ports, USB 3.0 ports, lots of expansion slots, great motherboard.

Memory - Corsair Vengeance 8GB (2x4GB) 1600MHz


Good value RAM modules with low latency.

Graphics Card - Sapphire R9 270X Dual-X 2GB edition


Again great value card that sails through almost all current games at 1080p without breaking a sweat.
I was not sure if the card will get hot, but during full load has reached 53C, which is good in a tropical country as India.

HDD - Western Digital Caviar Green 1 TB SATA 3


I trust WD more than any other brand. So no brainer here.

PSU - Antec VP550P 550W


A highly recommended PSU from different tech sites that gives ample options in terms of connectivity. I think this is one important component in your PC build, which people ignore, especially in India.

Case - Antec VSK-4000-U3


Good case with great build quality with lot of cooling options.

And here are some pictures.
The box looks pretty neat. I like it clean and simple. No bling.
The box has matte finish with good build quality
Stickers, I love stickers
Power supply unit is bad ass
Standard layout for a graphics card.
Tried to keep it neat as much as possible

The cooling fan came as a standard
Plenty of room for beefier cards













The all new Movie Central

Movie Central

A free desktop personal movie collection manager

Hi folks,

After a long time, I am glad to release the all new Movie Central desktop app for Windows.

  • All new fresh look, a new experience.
  • The most fun way to manage your personal movie collection.
  • Automatically scan your PC folders for movies, and add them to your collection.
  • Movies can be played from the app itself.







Guided Tour


 

Download links


Download Movie Central

Project website

Contact me






New Movie Central app in development....right now !!!

Hello Folks,

After pretty long gap, I have started on development of a new version of Movie Central app. Here is a screenshot, nightly build.

And it will be kick-ass.

Set perfect wallpapers for Nexus 7

I have a Google Nexus 7 2013 version. It's a hands down great device with a great display. I also love to change the wallpaper on the home screen regularly.
Problem is I wasn't able to figure out the perfect wallpaper resolution for the device. I used 1080p photos but at the lock screen, a bit of the screen space is left out, which was annoying for me.
So I found a simple solution. Rotate the device in landscape mode and then set the wallpaper from the "Settings" menu as you would normally do. Go back and lock the screen now and rotate it to portrait mode. The wallpaper should take up whole screen space.

PowerShell script to check user in Active Directory

 Here is a quick PowerShell script to check for user in present in Active Directory.

$user = "JohnDoe"
$searcher =  [ADSISearcher]"(sAMAccountName=$user)"
$results =  $Searcher.FindOne()
If ($results -eq $Null) 

    {"User does not exists"}
Else 

    {"User Exists"}


Same can be done using the user email

$email = "JohnDoe@company.com"
$searcher =  [ADSISearcher]"(mail=$email)"
$results =  $Searcher.FindOne()
If ($results -eq $Null) 

    {"User does not exists"}
Else 

    {"User Exists"}


It can be extended more to retrieve more information on the user. For example if the user account is active in AD.

$email = "JohnDoe@company.com"
$searcher =  [ADSISearcher]"(&(mail=$email)(userAccountControl:1.2.840.113556.1.4.803:=2))"
$results =  $searcher.FindOne()
If ($results -eq $Null) 

    {"User account is enabled"}
Else 

    {"User account is disabled"}


If we want to do this operation in bulk, we can put all the email ids in a text file. Each email id goes to each line as below in the text file.
 
JohnDoe@company.com
BruceWayne@company.com
PeterParker@company.com
...
...

Save the text file and give it some name...say "ADCheckUser.txt". And get our script running as below.

ForEach ($Email in Get-Content "ADCheckUser.txt")
{
    $Searcher =  [ADSISearcher]"(&(mail=$Email)(userAccountControl:1.2.840.113556.1.4.803:=2))"
    $Results =  $Searcher.FindOne()
    If ($Results -eq $Null) 

        {"User account is enabled"}
    Else 

        {"User account is disabled"}
}

SharePoint - Basic concepts about SharePoint Farms

People often have different ways of describing what exactly a SharePoint farm is. There are different ways of describing the Application server and the Web-Front End (WFE) server. As a developer, it is very important to understand the basics concept of the term 'farm' because when a solution is developed, it will be eventually be deployed in the servers present in the 'farm'.

What is a farm?

In the context of SharePoint, the term 'farm' is used to describe a collection of one or more SharePoint servers and one or more SQL servers that come together to provide a set of basic SharePoint services bound together by a single Configuration Database in SQL.
Farms can range in size from having everything (all SharePoint roles and SQL server) on one machine to scaling out every individual SharePoint serve role onto dedicated sets of servers. A farm the highest administrative boundary for SharePoint and everything that happens inside SharePoint happens in a farm.
An easy way to conceptualize is that one configuration database stands for one farm.

Server Services

Within a farm, there are several services that run on one or more servers. Some of these services are mandatory and some are optional. These services provide the underpinning functionality for SharePoint. The decision around which services run on which servers will have a huge impact on your overall farm architecture and performance.  
  • Windows SharePoint Services Web Application (often referred to as 'Web Server' or 'WFE') - This service is responsible for serving the HTML to clients and routing requests to other services in the farm.
  • Office SharePoint Server Search in Query Mode (often referred to as 'Query Server') - This service is responsible for executing search queries against a locally stored copy of the index
  • Office SharePoint Server Search in Index Mode (often referred to as 'Index Server')  - This service is responsible for indexing all of the configured content sources, creating an index and propagating it to every Query server in the farm
  • Windows SharePoint Services Search - This service is basically a slimmed down version of the Office SharePoint Server Search service which combines both the Query and Index roles into a single service.  
  • Excel Calculation Services - This service is responsible for performing calculations on Excel workbooks that are stored in the content databases.
  • Document Conversions Load Balancer Service  - This service balances document conversion requests from across the server farm. 
  • Document Conversions Launcher Service  - This service schedules and initiates the document conversions on a server.
  • Windows SharePoint Services Incoming E-Mail - This service is responsible for receiving incoming emails and placing them in email enabled lists. 
  • Windows SharePoint Services Outgoing E-Mail  - This is not technically a SharePoint service but refers to an SMTP server which SharePoint send outbound email to
  • Central Administration - This service enables the central administration interface that is required for farm-wide administration.

What is the difference between Application server & Web Front End (WFE) server?

When SharePoint is installed, you have to select one of three installation options, they are:
  • Application Server
  • Complete
  • Web Front End
There is a lot of confusion around what these options mean. An 'Application Server' is a server that is capable of running any of the services in the table above apart from the Windows SharePoint Services Web Application service. A 'Web Front End' (sometimes called a WFE) is the opposite in that it can only run the Windows SharePoint Services Web Application service. 'Complete' means that the server can run any SharePoint service.
The reason behind these options is that in some scenarios, very 'thin' web servers may be required which have a very small installation footprint. In this case, it is not desirable to install all of the DLLs etc that are required to run any service apart from the Windows SharePoint Services Web Application – these are true web servers. In my experience, this is a relatively rare scenario and only really relevant when SharePoint is being used to host high traffic internet sites.
The problem with selecting anything other than 'Complete' is that it means if you ever change your mind about what services a server can run, you'll need to re-install SharePoint on that server. For that reason alone, I would always recommend that you choose 'Complete' unless you have a very good reason to do otherwise.
This means that the terms 'Web Front End Server' and 'Application Server' are often used incorrectly. Unless your server is only running the Windows SharePoint Services Web Application service, it is an Application server. This means that the majority of servers in the majority of farms are actually Application servers.