Let's start with Provider Hosted MVC App with AngularJS - Part 2. In this part we are going to perform CRUD operation's with SharePoint APP Model and AngularJS.
Please Reference below link to understand how to create Provider Hosted MVC App With AngularJS.
SharePoint HostWeb List Structure
The following is a list structure which we are referencing for our application.
We are going to create the following CRUD operation UI Design and final output format.
Lets start with user data entry form design. when we are saying user entry form, it means we need to have validation applied to controls.
AngularJS validation logic reside in specific JavaScript file named angular-messages.js, so we need to add reference of that file in our project first.
When we think about validation, <form></form> control comes in existence. When end user enter valid data and submits data to the server, other stay on same page till the user fill correct form entries.
Let's check the following code & try to understand which property is used for which purpose in code.
Step 1: Add form tag with unique name so we can reference that name to check state of form- Valid/InValid.
- <form name="EmployeeForm" class="elegant-aero">
Step 2: Steps to apply AngularJS validation attributes and showing the error message
Add html control with unique name. If the form field is required, then add "
required " attribute to it.
Error Message: The ngModel directive expose an $error object. We can integrate
$errro object with
ngMessages to display control error message in easy way.
- ng-message="required": It corresponds to attribute we added to HTML control.
- <input type="text" class="form-control" ng-model="Employee.EmpID" name="EmployeeID" required />
-
- <div ng-messages="EmployeeForm.EmployeeID.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- ng-message="pattern": It corresponds to error message if specified pattern is not matching with user input data.
- <input type="text" class="form-control" ng-model="Employee.EmpAge" name="EmployeeAge" ng-pattern="/^[0-9]+$/" required />
-
-
- <div ng-messages="EmployeeForm.EmployeeAge.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- <div ng-message="pattern" class="ErrorText">Must be a digit</div>
- </div>
-
Save Button
In the starting save button is disabled. When user fills the form with valid data, save button gets activated.
- <button ng:click="save($event)" ng:disabled="isSaveDisabled()" class="btn btn-small btn-primary">Save </button>
JS code
The following code indicates how to check form state and return value as true or false.
- $scope.isSaveDisabled = function () {
-
- var Status = this.EmployeeForm.$invalid;
- return Status;
When above method i.e "
isSaveDisabled " returns true, control goes to save method with current employee details as input parameter.
Form control:
- <form name="EmployeeForm" class="elegant-aero">
- <table class="table table-condensed table-striped table-bordered">
- <tr>
- <td class="LblColumn">Employee Id:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpID" name="EmployeeID" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeID.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- </td>
- </tr>
- <tr>
- <td class="LblColumn">Employee Name:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpName" name="EmployeeName" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeName.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- </td>
- </tr>
- <tr>
- <td class="LblColumn">Employee Address:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpAddress" name="EmployeeAddress" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeAddress.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- </td>
- </tr>
- <tr>
- <td class="LblColumn">Employee Age:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpAge" name="EmployeeAge" ng-pattern="/^[0-9]+$/" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeAge.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- <div ng-message="pattern" class="ErrorText">Must be a digit</div>
- </div>
- </td>
- </tr>
- <tr>
- <td class="LblColumn">Employee Qualification:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpQualification" name="EmployeeQualification" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeQualification.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- </td>
- </tr>
- <tr>
- <td class="LblColumn">Employee Designation:</td>
- <td class="DataColumn">
- <input type="text" class="form-control" ng-model="Employee.EmpDesignation" name="EmployeeDesignation" required />
- </td>
- <td class="ErrorColumn">
- <div ng-messages="EmployeeForm.EmployeeDesignation.$error">
- <div ng-message="required" class="ErrorSymbol">*</div>
- </div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- @*<input type="button" id="btnaddcategory" value="Save" ng-click="save($event)" class="btn btn-small btn-primary" />*@
- <button ng:click="save($event)" ng:disabled="isSaveDisabled()" class="btn btn-small btn-primary">Save </button>
- </td>
- <td>
- <input type="text" class="form-control" ng-model="Employee.ID" style="visibility:hidden">
- </td>
- </tr>
- </table>
- lt;/form>
Table Control We want to perform CRUD operation so need to add update & delete button. Therefore, I added that button to table via AngularJS.
Article Part-1 <table></table> control and this table control you notice some difference here.
Inside
<tbody></tbody> control I added a row with two column , first for Update button & second for Delete button.
- Update button: ng-click="loadRecord(gridItem, $event)".
- Delete button: ng-click="DeleteItem(gridItem.ID, $event)".
- <table tr-ng-grid="" items="EmployeeMaster" locale="en">
- <thead>
- <tr>
- <th field-name="EmpID" display-name="Employee ID"></th>
- <th field-name="EmpName" display-name="Employee Name"></th>
- <th field-name="EmpAddress" display-name="Address"></th>
- <th field-name="EmpAge" display-name="Age"></th>
- <th field-name="EmpQualification" display-name="Qualification"></th>
- <th field-name="EmpDesignation" display-name="Designation"></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <input type="button" id="btnUpdatEmployee" class="btn btn-success"
- value="Update"
- ng-click="loadRecord(gridItem, $event)" />
- </td>
- <td>
- <input type="button" id="btnDeleteEmployee" class="btn btn-success"
- value="Delete"
- onclick="javascript: confirm('Do you want to delete record ??');"
- ng-click="DeleteItem(gridItem.ID, $event)" />
- </td>
- </tr>
- </tbody>
- </table>
Index.cshtml Source Code
Please check below the following source code changes like new script reference, <table> control change,<form> control integration in order to design above UI.
CRUD Operation JavaScript Code
In
Part -1 , Read function has completed i.e Load() method. some new method need to added here.
Note - We loaded all out of box JS file in Load() function at start so no need to load same file again and again, otherwise it gives you error or nothing happens.
app-main.js:
We first need to modify Dependent module names, since we want to apply validation to html control, '
ngMessages' need to be added as dependent module.
- (function () {
-
- console.log('app-main.js loaded ..');
-
- angular.module(window.AngularApp_constants.architecture.modules.MainApp.moduleKey, ['trNgGrid', 'ngMessages']);
-
- })();
app-home-controller.js: I will explain all function of "app-home-controller.js" file first and then we move to DataLayer functions.
For better programming purpose, we are going to integrate Save() and Update() functionality in a single function based on flag value. IsUpdate flag set to false at start, when needed this flag value get changed.
When Save button is clicked, as per flag value, either of the function get called.
- $scope.IsUpdate = false;
-
- $scope.Employee = {
- ID: '',
- EmpID: '',
- EmpName: "",
- EmpAddress: "",
- EmpAge: "",
- EmpQualification: "",
- EmpDesignation : ""
- };
-
- $scope.save = function ($event) {
-
- $event.preventDefault();
-
- if (!$scope.IsUpdate) {
-
- var promiseSave = AngularDataService.save($scope.Employee);
- window.location.reload();
- }
- else {
-
- var promiseUpdate = AngularDataService.update($scope.Employee);
- window.location.reload();
- }
- }
When Update button is clicked, loadRecord() function get called.
-
-
- $scope.loadRecord = function (Emp, $event) {
- $event.preventDefault();
-
- $scope.Employee.ID = Emp.ID;
- $scope.Employee.EmpID = Emp.EmpID;
- $scope.Employee.EmpName = Emp.EmpName;
- $scope.Employee.EmpAddress = Emp.EmpAddress;
- $scope.Employee.EmpAge = Emp.EmpAge;
- $scope.Employee.EmpQualification = Emp.EmpQualification;
- $scope.Employee.EmpDesignation = Emp.EmpDesignation;
-
- $scope.IsUpdate = true;
- }
When Delete button is clicked, DeleteItem() function get called.
-
-
- $scope.DeleteItem = function (ItemID, $event) {
-
- var promiseDelete = AngularDataService.delete(ItemID);
- }
app-home-controller.js source code - (function () {
-
- console.log('app-home-controller.js loaded ..');
- 'use strict'
-
- angular
- .module(window.AngularApp_constants.architecture.modules.MainApp.moduleKey)
- .controller('HomeController', HomeController)
-
- HomeController.$inject = ['$scope', '$location', 'app-data-service'];
-
- function HomeController($scope, $location, AngularDataService) {
-
-
- $scope.EmployeeMaster = [];
-
- Load();
-
- function Load() {
-
- console.log("Load called");
-
- var promiseGet = AngularDataService.get();
- promiseGet.then(function (resp) {
- $scope.EmployeeMaster = resp;
- }, function (err) {
- $scope.Message = "Error " + err.status;
- });
- }
-
-
-
- $scope.IsUpdate = false;
-
- $scope.Employee = {
- ID: '',
- EmpID: '',
- EmpName: "",
- EmpAddress: "",
- EmpAge: "",
- EmpQualification: "",
- EmpDesignation : ""
- };
-
- $scope.save = function ($event) {
-
- $event.preventDefault();
-
- if (!$scope.IsUpdate) {
-
- var promiseSave = AngularDataService.save($scope.Employee);
- window.location.reload();
- }
- else {
-
- var promiseUpdate = AngularDataService.update($scope.Employee);
- window.location.reload();
- }
- }
-
-
-
- $scope.loadRecord = function (Emp, $event) {
- $event.preventDefault();
-
- $scope.Employee.ID = Emp.ID;
- $scope.Employee.EmpID = Emp.EmpID;
- $scope.Employee.EmpName = Emp.EmpName;
- $scope.Employee.EmpAddress = Emp.EmpAddress;
- $scope.Employee.EmpAge = Emp.EmpAge;
- $scope.Employee.EmpQualification = Emp.EmpQualification;
- $scope.Employee.EmpDesignation = Emp.EmpDesignation;
-
- $scope.IsUpdate = true;
- }
-
-
-
- $scope.DeleteItem = function (ItemID, $event) {
-
- var promiseDelete = AngularDataService.delete(ItemID);
- }
-
-
-
- $scope.isSaveDisabled = function () {
-
- var Status = this.EmployeeForm.$invalid;
- return Status;
- }
- }
-
- })();
app-data-service.js When we want to save employee record, we need to call save() function of DataLayer.
-
- his.save = function (Employee) {
-
- var deferred = $q.defer();
-
- try {
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
- var listCreationInformation = new SP.ListItemCreationInformation();
-
- ctx.load(list);
- var listItem = list.addItem(listCreationInformation);
-
- listItem.set_item("EmpID", Employee.EmpID);
- listItem.set_item("EmpName", Employee.EmpName);
- listItem.set_item("EmpAddress", Employee.EmpAddress);
- listItem.set_item("EmpAge", Employee.EmpAge);
- listItem.set_item("EmpQualification", Employee.EmpQualification);
- listItem.set_item("EmpDesignation", Employee.EmpDesignation);
-
- listItem.update();
- ctx.load(listItem);
-
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item Created');
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message()+'\n' + args.get_stackTrace());
- })
- );
- }
- catch (Error) {
- console.log("Error : " + Error);
- }
-
- return deferred.promise;
- ;
When we want to update employee record, we need to call update() function of DataLayer.
-
- this.update = function (Employee) {
-
- var deferred = $q.defer();
-
- try {
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
-
- var listItem = list.getItemById(Employee.ID);
- ctx.load(listItem);
-
- listItem.set_item("EmpID", Employee.EmpID);
- listItem.set_item("EmpName", Employee.EmpName);
- listItem.set_item("EmpAddress", Employee.EmpAddress);
- listItem.set_item("EmpAge", Employee.EmpAge);
- listItem.set_item("EmpQualification", Employee.EmpQualification);
- listItem.set_item("EmpDesignation", Employee.EmpDesignation);
-
- listItem.update();
-
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item Updated');
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- })
- );
- }
- catch (Error) {
- console.log("Error : " + Error);
- }
- return deferred.promise;
- }
When we want to update employee record, we need to call delete() function of DataLayer.
-
- this.delete = function (EmpID) {
-
- var deferred = $q.defer();
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
-
- var itemId = EmpID;
- listItem = list.getItemById(itemId);
- listItem.deleteObject();
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item deleted: ' + itemId);
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- })
- );
-
- return deferred.promise;
- }
-
app-data-service.js source code - (function () {
-
- console.log('app-data-service.js loaded...');
- 'use strict'
-
- angular
- .module(window.AngularApp_constants.architecture.modules.MainApp.moduleKey)
- .service('app-data-service', AngularDataService);
-
- AngularDataService.$inject = ['$q', '$http', '$timeout'];
-
- function AngularDataService($q, $http, $timeout) {
-
- function QueryStringParameter(paramToRetrieve) {
- var params =
- document.URL.split("?")[1].split("&");
- var strParams = "";
- for (var i = 0; i < params.length; i = i + 1) {
- var singleParam = params[i].split("=");
- if (singleParam[0] == paramToRetrieve) {
- return singleParam[1];
- }
- }
- }
-
- var hostweburl;
- var appweburl;
-
-
- hostweburl = decodeURIComponent(QueryStringParameter('SPHostUrl'));
-
-
- appweburl = decodeURIComponent(QueryStringParameter('SPAppWebUrl'));
-
-
- var scriptbase = hostweburl + "/_layouts/15/";
- var listTitle = "EmployeeCatalog";
-
-
-
- this.get = function () {
-
- var EmployeeArray = [];
-
- var deferred = $q.defer();
-
-
- $.getScript(scriptbase + "SP.Runtime.js",
- function () {
- $.getScript(scriptbase + "SP.js",
- function () {
- $.getScript(scriptbase + "SP.RequestExecutor.js",
- function () {
-
-
- var context = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- context.set_webRequestExecutorFactory(factory);
-
- var appContextSite = new SP.AppContextSite(context, hostweburl);
- var web = appContextSite.get_web();
- context.load(web);
-
-
- var list = web.get_lists().getByTitle(listTitle);
-
- var camlQuery = SP.CamlQuery.createAllItemsQuery();
- this.listItems = list.getItems(camlQuery);
- context.load(this.listItems);
-
- context.executeQueryAsync(
- Function.createDelegate(this, function () {
-
- var ListEnumerator = this.listItems.getEnumerator();
-
- while (ListEnumerator.moveNext()) {
-
- var currentItem = ListEnumerator.get_current();
- EmployeeArray.push({
- ID: currentItem.get_item('ID'),
- EmpID: currentItem.get_item('EmpID'),
- EmpName: currentItem.get_item('EmpName'),
- EmpAddress: currentItem.get_item('EmpAddress'),
- EmpAge: currentItem.get_item('EmpAge'),
- EmpQualification: currentItem.get_item('EmpQualification'),
- EmpDesignation: currentItem.get_item('EmpDesignation')
- });
- }
-
- console.log(EmployeeArray);
- deferred.resolve(EmployeeArray);
- }),
- Function.createDelegate(this, function (sender, args) {
- deferred.reject('Request failed. ' + args.get_message());
- console.log("Error : " + args.get_stackTrace());
- })
- );
- });
- });
- });
-
- return deferred.promise;
- };
-
-
-
- this.save = function (Employee) {
-
- var deferred = $q.defer();
-
- try {
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
- var listCreationInformation = new SP.ListItemCreationInformation();
-
- ctx.load(list);
- var listItem = list.addItem(listCreationInformation);
-
- listItem.set_item("EmpID", Employee.EmpID);
- listItem.set_item("EmpName", Employee.EmpName);
- listItem.set_item("EmpAddress", Employee.EmpAddress);
- listItem.set_item("EmpAge", Employee.EmpAge);
- listItem.set_item("EmpQualification", Employee.EmpQualification);
- listItem.set_item("EmpDesignation", Employee.EmpDesignation);
-
- listItem.update();
- ctx.load(listItem);
-
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item Created');
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- })
- );
- }
- catch (Error) {
- console.log("Error : " + Error);
- }
-
- return deferred.promise;
- };
-
-
- this.update = function (Employee) {
-
- var deferred = $q.defer();
-
- try {
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
-
- var listItem = list.getItemById(Employee.ID);
- ctx.load(listItem);
-
- listItem.set_item("EmpID", Employee.EmpID);
- listItem.set_item("EmpName", Employee.EmpName);
- listItem.set_item("EmpAddress", Employee.EmpAddress);
- listItem.set_item("EmpAge", Employee.EmpAge);
- listItem.set_item("EmpQualification", Employee.EmpQualification);
- listItem.set_item("EmpDesignation", Employee.EmpDesignation);
-
- listItem.update();
-
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item Updated');
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- })
- );
- }
- catch (Error) {
- console.log("Error : " + Error);
- }
- return deferred.promise;
- }
-
-
- this.delete = function (EmpID) {
-
- var deferred = $q.defer();
-
- var ctx = new SP.ClientContext(appweburl);
-
-
- var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
- ctx.set_webRequestExecutorFactory(factory);
-
- var appCtxSite = new SP.AppContextSite(ctx, hostweburl);
- var web = appCtxSite.get_web();
-
- var list = web.get_lists().getByTitle(listTitle);
-
- var itemId = EmpID;
- listItem = list.getItemById(itemId);
- listItem.deleteObject();
-
- ctx.executeQueryAsync(
- Function.createDelegate(this, function () {
- console.log('Item deleted: ' + itemId);
- }),
- Function.createDelegate(this, function (sender, args) {
- console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- })
- );
-
- return deferred.promise;
- }
-
-
- }
-
- })();
I hope you all liked this article as you liked the
Part-1 of this series.