Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

SPA with AngularJS in .NET

4.81/5 (15 votes)
13 Sep 2015CPOL7 min read 42.2K   1.9K  
This is two part demo, in first part I will be showing how to insert a record into database and get all the records from database, and display. Part 2 I will show delete and update operations.

I tried to learn Single Page Application (SPA) from online and they are good ones for the starters with mainly CRUD operations on only one database table. In real time there will be lot of tables you have to retrieve data from and insert into and I couldn't find any such article. So, I have decided to create on my own and thanks to my project manager who has asked me to show demo of SPA using AngularJS framework.

This is two part demo, in first part I will be showing, how to insert a record into database and get all the records from database, and display. Part 2 I will show delete and update operations.

Article Overview: CRUD operations on multiple database tables in SPA.

Introduction

Now a day's user wants to faster web application with Rich UI and able to access app from multiple gadgets (like Tablets, Mobiles etc.). With help of HTML5, JQuery or JavaScript frameworks and AJAX it is possible to develop SPA.

What is SPA in Reality

In simple words it is nothing but a web application with one parent page and child pages (partial views) are loaded based on demand. In SPA all the required resources are loaded with initial request and rest of the resources are loaded based on demand.

SPA vs Traditional Web App’s

Traditional Web App’s

As you can see in below image the traditional app’s whenever user request, it goes back to server and render’s new page with page reload.

Image 1

Source: https://msdn.microsoft.com/en-us/magazine/dn463786.aspx?f=255&MSPPError=-2147217396

SP App

In SPA when user request page, it will dynamically load and calls to server will be done through Ajax and data is retrieved by JSON. In SPA data rendering and routing is done on client side, which makes very responsive just like desktop apps.

Image 2

Source: http://www.slideshare.net/hsplmkting/benefits-of-developing-single-page-web-applications-using-angular-js

Advantages of SPA

  • No page flicker. Native application feel.
  • Client side routing and data rendering on client side.
  • Data is from server is in JSON format.

Disadvantages of SPA

  • User must enable JavaScript.
  • Security.

Creating project in visual studio

In this demo I have used VS 2012, .NET framework 4.5, AngularJS, Bootstrap and .mdf file for database operation. I have provided all necessary screen shot and source code to download.

Open Visual Studio 2012 and create project with MVC4 template, I have named the project as SingePageAngularJS but you can name it anything as you like.

Image 3

Adding JQuery and AngularJS

Figure below shows I installed Bootstrap, AngularJS and Angular routing from NuGet packages. And added new folder in scripts folder named it as App and added new JavaScript file called myApp. I will be adding angularJS code in myApp later on.

Image 4

Now add these installed files to your MVC project. Go To -> App_Start -> BundleConfig. Add below lines like I have showed in red rectangle in the below figure.

Image 5

Now you have to make sure these files are added in your Master page (_Layout.cshtml) which is located in Views -> Shared folder of the application. I always put my JQuery or required files inside the head tag of my project, to make it accessible to you entire application as shown in the below image.

Image 6

So, now we have added JQuery, angular, angular routing, bootstrap css and bootstrap.js files in our layout page and we need to make sure they are rendered on our browser properly without any errors. To double check run the application in chrome browser and press F12 to open browser tools. Check all the files are loaded by clicking on Sources tab and check there are no errors on console tab. Below figure confirms all files are loaded properly with no errors in console tab.

Image 7

Setting up Database

I will add .mdf file for database operations and named it has AngularDB.mdf. In .mdf file I have created two tables (EmpDetails and EmpAddress) and scripts are provided below. EmpDetails table contains employee information and EmpAddress contains employee multiple address. Between these two tables we have foreign key relation with EmpId because whenever you select employee I wanted to display all the addresses of the particular employee.

EmpDetails Table

SQL
CREATE TABLE [dbo].[EmpDetails] (
    [EmpID]    INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]  VARCHAR (50) NULL,
    [EmpPhone] VARCHAR (50) NULL,
    PRIMARY KEY CLUSTERED ([EmpID] ASC)
);

EmpAddress Table

SQL
CREATE TABLE [dbo].[EmpAddress] (
    [EmpAddressId] INT           IDENTITY (1, 1) NOT NULL,
    [Address1]      VARCHAR (500) NULL,
    [Address2]      VARCHAR (500) NULL,
    [Address3]      VARCHAR (500) NULL,
    [EmpID]        INT           NULL,
    PRIMARY KEY CLUSTERED ([EmpAddressId] ASC),
    FOREIGN KEY ([EmpID]) REFERENCES [dbo].[EmpDetails] ([EmpID])
);

Note: In this application my concentration is not only on CRUD operations but also to show how to display data from multiple tables to UI and pass data to multiple tables.

MVVM Pattern

For this demo I will be using MVVM pattern for both in angularJS script and visual studio. The image below shows I have created folder called ViewModels (it has references of multiple models) and add two models in the models folder, and I name them as EmpDetailsModel and EmpAddressModel.

Image 8

Angularjs Code

In previous section we have done with database related stuff. Now we jump into main topic of this demo.

In Adding Jquery and Angularjs: we have created myApp.js file and left it empty, just copy and paste below code in it.

JavaScript
angular.module('App', ['AngularDemo.EmpAddController',
                       'AngularDemo.AddressController',
                       'AngularDemo.DeleteController'
])

.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {

    $routeProvider.when('/', {
        templateUrl: '/Home/AddEmployee',
        controller: 'EmpAddCtrl',
    });
    $routeProvider.when('/Edit', {
        templateUrl: '/Home/EditEmployee',
        controller: 'EditCtrl'
    });
    $routeProvider.when('/Delete', {
        templateUrl: '/Home/DeleteEmployee',
        controller: 'DeleteCtrl'
    });
    $routeProvider.otherwise({
        redirectTo: '/'
    });
    // Specify HTML5 mode (using the History APIs) or HashBang syntax.
    $locationProvider.html5Mode(false).hashPrefix('!');

}]);

//Add Employee Controller
angular.module('AngularDemo.EmpAddController', ['ngRoute'])
.controller('EmpAddCtrl', function ($scope, $http) {

    $scope.EmpAddressList = {};
    $http.get('/Home/ShowEmpList').success(function (data) {
        $scope.EmpAddressList = data;
      
    });


    $scope.EmpDetailsModel =
     {
         EmpID: '',
         EmpName: '',
         EmpPhone: ''
     };

    $scope.EmpAddressModel =
    {
        Address1: '',
        Address2: '',
        Address3: ''
    };

    $scope.EmployeeViewModel = {
        empDetailModel: $scope.EmpDetailsModel,
        empAddressModel: $scope.EmpAddressModel
    };


    $scope.AddEmployee = function () {
        //debugger;
        $.ajax({
            url: '/Home/AddEmpDetails',
            type: 'POST',
            dataType: 'json',
            contentType: 'application/json',
            traditional: true,
            data: JSON.stringify({ EmployeeViewModelClient: $scope.EmployeeViewModel }),
            success: function (data) {
                $scope.EmpAddressList.push(data[0]);
                $scope.$apply();
                //$scope.$apply();
                alert("Record is been added");
            }
        });
    };
});


//Address Controller
angular.module('AngularDemo.AddressController', ['ngRoute'])
.controller('EditCtrl', function ($scope, $http) {
    $scope.Message = "Edit in Part 2 is coming soon";
});

angular.module('AngularDemo.DeleteController', ['ngRoute'])
.controller('DeleteCtrl', function ($scope, $http) {
    $scope.Message = "Delete in Part 2 is coming soon";
});

Angular Code Explaination:

JavaScript
angular.module('App', ['AngularDemo.EmpAddController',
                       'AngularDemo.AddressController',
                       'AngularDemo.DeleteController'
])

Note: The angular.module is a global place for creating, registering and retrieving Angular modules. All modules that should be available to an application must be registered using this mechanism. (https://docs.angularjs.org/api/ng/function/angular.module).

1st parameter is the name of your angular app, for our demo it is named as ‘App’.

2nd parameter is array of dependencies, we have only three dependencies currently that is 'AngularDemo.EmpAddController', 'AngularDemo.AddressController' and 'AngularDemo.DeleteController'.

ng-app directive: Once you name your angularJS you have to use in your html page depending up on your requirements. For this demo I have used ng-app in _Layout page in html tag like shown below.

Image 9

Client-side Routing

So, we have defined the name of our angularJS app and mentioned array of dependencies. Now, let’s create routing at the client side. For this I have created three routes as below with templateUrl and controller.

JavaScript
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {

    $routeProvider.when('/', {
        templateUrl: '/Home/AddEmployee',
        controller: 'EmpAddCtrl',
    });
    $routeProvider.when('/Edit', {
        templateUrl: '/Home/EditEmployee',
        controller: 'EditCtrl'
    });
    $routeProvider.when('/Delete', {
        templateUrl: '/Home/DeleteEmployee',
        controller: 'DeleteCtrl'
    });
    $routeProvider.otherwise({
        redirectTo: '/'
    });
    // Specify HTML5 mode (using the History APIs) or HashBang syntax.
    $locationProvider.html5Mode(false).hashPrefix('!');

}]);

Whenever, angularJS finds the url which was mentioned in routing, it goes corresponding angularJS controller, where we have to create models and Ajax calls to server. Below is the controller code.

JavaScript
//Add and display Employee Controller
angular.module('AngularDemo.EmpAddController', ['ngRoute'])
.controller('EmpAddCtrl', function ($scope, $http) {

$scope.EmpDetailsModel =
     {
         EmpID: '',
         EmpName: '',
         EmpPhone: ''
     };

    $scope.EmpAddressModel =
    {
        Address1: '',
        Address2: '',
        Address3: ''
    };

    $scope.EmployeeViewModel = {
        empDetailModel: $scope.EmpDetailsModel,
        empAddressModel: $scope.EmpAddressModel
    };

    $scope.EmpAddressList = {};
    $http.get('/Home/ShowEmpList').success(function (data) {
        $scope.EmpAddressList = data;
    });
   
    $scope.AddEmployee = function () {
        $.ajax({
            url: '/Home/AddEmpDetails',
            type: 'POST',
            dataType: 'json',
            contentType: 'application/json',
            traditional: true,
            data: JSON.stringify({ EmployeeViewModelClient: $scope.EmployeeViewModel }),
            success: function (data) {
                $scope.EmpAddressList.push(data[0]);
                $scope.$apply();
                alert("Record is been added");
            }
        });
    };
});

$scope is responsible for setting model properties and functions/behaviour of particular controller.

In EmpAddCtrl controller we have two models(EmpDetailsModel, EmpAddressModel) and viewmodel (EmployeeViewModel) where we will be passing this viewmodel to server to save data to database, using $scope.AddEmployee function and $http.get will get all the list of records on pageloads.

Views: Now we have done with angularJS we have to use this in html pages. So, this is what my _layout page looks like. _Layout.html

HTML
<!DOCTYPE html>
<html lang="en" ng-app="App">
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/angular")
    @Scripts.Render("~/bundles/CustomAngular")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    <header>
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                                    </div>
                <div id="navbar" class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li class="active"><a href="#!/">Add</a></li>
                        <li><a href="#!/Address">Edit/Update</a></li>
                        <li><a href="#!/Delete">Delete</a></li>
                    </ul>
                    
                </div>
                <!--/.nav-collapse -->
            </div>
        </nav>
    </header>
    <div id="body">
        @RenderSection("featured", required: false)
        <section class="content-wrapper main-content clear-fix">
            @RenderBody()
        </section>
    </div>

    @RenderSection("scripts", required: false)


</body>
</html>

Index.html page

Just copy below code and paste it in index html page. ng-view is place holder where the partial views are dynamically loaded.

HTML
<div ng-view="" ></div>

AddEmployee.html partial page

Copy below code and paste it in your AddEmployee partial view. In this view user can add new employee and address information and it also display list of employees in grid format.

The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

HTML
<div style="width: 50%; margin: 50px auto;">

    <table>
        <tr>
            <td>
                <strong>Employee Name:</strong>
            </td>
            <td>
                <input type="text" class="form-control" ng-model="EmpDetailsModel.EmpName" placeholder="Employee Name" />
            </td>
        </tr>
        <tr>
            <td>
                <strong>Employee Phone:</strong>

            </td>
            <td>
                <input type="text" class="form-control" ng-model="EmpDetailsModel.EmpPhone" placeholder="Employee Phone" />
            </td>
        </tr>
        <tr>
            <td>
                <strong>Address 1:</strong>

            </td>
            <td>
                <input type="text" class="form-control" ng-model="EmpAddressModel.Address1" placeholder="Address 1" />
            </td>
        </tr>
        <tr>
            <td>
                <strong>Address 2:</strong>

            </td>
            <td>
                <input type="text" class="form-control" ng-model="EmpAddressModel.Address2" placeholder="Address 2" />
            </td>
        </tr>

        <tr>
            <td>
                <strong>Address 3:</strong>

            </td>
            <td>
                <input type="text" class="form-control" ng-model="EmpAddressModel.Address3" placeholder="Address 3" />
            </td>
        </tr>
        <br />
        <tr>
            <td>    
            </td>
            <td>
                <button type="button" ng-click="AddEmployee();" class="btn btn-primary">Save</button>
            </td>
        </tr>

    </table>
</div>

<hr style="color: black" />

<div style="width: 50%; margin: 50px auto;">
    <div class="panel panel-default">
        <!-- Default panel contents -->
        <div class="panel-heading"><b>Employee Details </b></div>
        <div class="table-responsive">
            <table id="EmployeeTable" class="table table-striped table-bordered table-hover table-condensed">
                <thead>
                    <tr>
                        <th>Employee Name</th>
                        <th>Employee Phone</th>
                        <th>Employee Address1</th>
                        <th>Employee Address2</th>
                        <th>Employee Address3</th>
                    </tr>
                </thead>
                <tbody>
                    <tr data-ng-repeat="Emp in EmpAddressList">

                        <td>{{Emp.empDetailModel.EmpName}}</td>
                        <td>{{Emp.empDetailModel.EmpPhone}}</td>
                        <td>{{Emp.empAddressModel.Address1}}</td>
                        <td>{{Emp.empAddressModel.Address2}}</td>
                        <td>{{Emp.empAddressModel.Address3}}</td>

                    </tr>

                    @*<tr ng-if="states.NewRow">*@
                    <tr ng-if="EmpAddressList.length == 0">
                        <td class="text-center" colspan="4">There are no Employee details to display
                        </td>
                    </tr>
                </tbody>
            </table>

        </div>
    </div>
    
</div>

Output screens

Now we have done with all our coding, just run by pressing F5 you can see below screenshot. Initially we don't have any data so, therefore it display's There are no Employee details to display.

Image 10

Save Button

Enter data of employee and address, when User clicks on save button, it triggers AddEmployee function in angularjs which calls corresponding controller action. Below image shows that we have entered information.

Image 11

Once user clicks on save, the view model is passed from angularjs to mvc controller action. I have two screen shots below to show data being passed to models (empDetailsModel and empAddressModel).

Image 12

After saving into database you will get confirmation saying record is been added.

Image 13

Database

The data we have entered on UI is been saved to database.

Image 14

Conclusion

Single page application will give you better performance when compared to traditional web apps. But, never compromise when it comes to security and you should think about security and take enough measures about it before developing single page applications.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)