DotNetCurry Logo

Using AngularJS and ASP.NET Web API for Searching Data in a Table/Grid

Posted by: Mahesh Sabnis , on 7/8/2015, in Category AngularJS
Views: 39892
Abstract: Use AngularJS to search a grid populated using ASP.NET WebAPI

The two-way data binding feature of Angular.js provides data updates notification to the model, when a change is made to the UI. In the following article, we will implement a criteria based search by using the $http service to make a call to ASP.NET WEB API.

 

Step 1: Open the free Visual Studio 2013 Community Edition and create a new empty MVC application of the name ‘NG_MVC_FIltering’. In this project, in the App_Data folder, add a new SQL Server database of the name ApplicationDB.mdf. In this database, add a new EmployeeInfo table with the following schema:

employee-info-table

Insert sample Data in this table, so that we can use it in our application. E.g. Insert data using the following SQL Statements:

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName]) 
VALUES (1, N'SRS Medicles', N'1122334455', N'Crocin', 1000, N'MS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName])
VALUES (2, N'SPR Medico', N'1223344556', N'Rosyday', 500, N'MS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName])
VALUES (3, N'MRT Healthcare', N'2121212112', N'Telma-AM', 784, N'LS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName])
VALUES (4, N'ABC Medi', N'1212121212', N'S-Numlo', 895, N'LS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName])
VALUES (5, N'PJ Health', N'4545454545', N'Crocin', 895, N'TS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName]) 
VALUES (7, N'SRS Medicles', N'1122334455', N'Rosyday', 7800, N'MS')

INSERT INTO [dbo].[OrderManager] ([OrderId], [CustomerName], 
[CustomerMobileNo], [OrderedItem], [OrderedQuantity], [SalesAgentName])
VALUES (10, N'MRT Healthcare', N'2121212112', N'Crocin', 950, N'MS')

Step 2: In the Models folder, add a new ADO.NET Entity Data model of the name ApplicationDBEDMX.edmx. Complete the wizard by selecting ApplicationDB.mdf and the EmployeeInfo table. After the completion of the wizard, the table mapping will get generated. Build the project and make sure that it is error free.

Step 3: In the Controllers folder, add a new empty ASP.NET WEB API controller of the name OrderManagerAPIController. Add the following code in it:

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

using NG_MVC_FIltering.Models;

namespace NG_MVC_FIltering.Controllers
{
    public class OrderManagerAPIController : ApiController
    {

        ApplicationDBEntities ctx;
        public OrderManagerAPIController()
        {
            ctx = new ApplicationDBEntities(); 
        }

        // Get all orders
        [Route("Orders")]
        public List<OrderManager> GetOrders()
        {
            return ctx.OrderManagers.ToList();
        }

        // Get Orders based on Criteria
        [Route("Orders/{filter}/{value}")]
        public List<OrderManager> GetOrdersByCustName(string filter,string value)
        {
            List<OrderManager> Res = new List<OrderManager>(); 
            switch (filter)
            {
                case "CustomerName":
                    Res = (from c in ctx.OrderManagers
                           where c.CustomerName.StartsWith(value)
                              select c).ToList();
                    break;
                case "MobileNo":
                    Res = (from c in ctx.OrderManagers
                           where c.CustomerMobileNo.StartsWith(value)
                          select c).ToList();
                    break;
                case "SalesAgentName":
                    Res = (from c in ctx.OrderManagers
                           where c.SalesAgentName.StartsWith(value)
                          select c).ToList();
                    break;
            }
            return Res;
        }
    }
}

In the above code, the method GetOrders() returns all orders and the method GetOrdersByCustName() accepts parameters which represent the filter criteria and its value. Based upon the filter name and its value, the query will be executed and the Orders will be returned.

Step 4: To implement the client-side logic, we need to add Angular.js, jQuery.js and Bootstrap.js libraries. The Bootstrap library is only need for styling the table. Since Bootstrap requires jQuery, we need to add jQuery too . Use the following commands from Package Manager Console to install NuGet Packages:

Install-Package angularjs

Install-Package jQuery

Install-Package bootstrap

Step 5: In the Controllers folder, add a new Empty MVC controller of the name OrdersController. We need to scaffold the Index view from the Index method of this controller. Right-click on this method and select option Add View from the Context menu. This will add Index.cshtml.

Step 6: In the Scripts folder, add a new folder of the name MyScripts. In this folder, add a new JavaScript file of the name Logic.js with the following code:

/// <reference path="../angular.intellisense.js" />

//The Module Declaration
var app = angular.module('ngmodule', []);

//Declaring Service
app.service('ngservice', function ($http) {
    //The function to read all Orders
    this.getOrders = function () {    
        var res = $http.get("/Orders");
        return res;
    };
    //The function to read Orders based on filter and its value
    //The function reads all records if value is not entered
    //else based on the filter and its value, the Orders will be returned
    this.getfilteredData = function (filter, value) {
 var res;        
if (value.length == 0) {
            res  = $http.get("/Orders");
            return res;
        } else {
            res = $http.get("/Orders/" + filter + "/" + value);
            return res;
        }
        
    };
});

//Declaring the Controller
app.controller('ngcontroller', function ($scope, ngservice) {
    $scope.Selectors = ["CustomerName", "SalesAgentName", "MobileNo"];
    $scope.SelectedCriteria = ""; //The Object used for selecting value from <option>
    $scope.filterValue = ""; //The object used to read value entered into textbox for filtering information from table

    loadOrders();

    //Function  to load all Orders
    function loadOrders() {
        var promise = ngservice.getOrders();
        promise.then(function (resp) {
            $scope.Orders = resp.data;
            $scope.Message = "Call is Completed Successfully";
        }, function (err) {
            $scope.Message = "Call Failed " + err.status;
        });
    };

    //Function to load orders based on a criteria
    $scope.gerFilteredData = function () {
        var promise = ngservice.getfilteredData($scope.SelectedCriteria, $scope.filterValue);
        promise.then(function (resp) {
            $scope.Orders = resp.data;
            $scope.Message = "Call is Completed Successfully";
        }, function (err) {
            $scope.Message = "Call Failed " + err.status;
        });
    };
});

The above code does the following:

  • Declares angular module of name ‘ngmodule’
  • Declares angular service of the name ‘ngservice’. This contains ‘getOrders()’ and ‘getfilteredData()’ functions. These functions make a call to Orders Web API and receives all Orders and Orders based on the filter criteria respectively
  • Declares angular controller of the name ‘ngcontroller’. This contains Selectors array which is initialized with the filter values e.g. CustomerName, SalesAgentName, etc. The function loadOrders() calls the getOrders() function from the service and receives all orders and stores them into the Orders scope object. The getFilteredData() function calls getfilteredData() function from the service and passes filter name and the value received from UI

Step 7: In the Index.cshtml, add the following Markup, Script references and the model binding expressions.

<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-2.1.4.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Scripts/MyScripts/Logic.js"></script>

<h1>Orders View</h1>
<div ng-app="ngmodule">
    <div ng-controller="ngcontroller">
        <table class="table table-bordered table-condensed">
            <tr>
                <td>Search By:</td>
                <td>
<select ng-model="SelectedCriteria" ng-options="S for S in Selectors">
                    </select>                </td>
                <td>Enter Search Value:</td>
                <td>
                    <input type="text" ng-model="filterValue" class="form-control" ng-change="getFilteredData()" />
                </td>
            </tr>
        </table>
        <table class="table table-bordered table-condensed table-striped">
            <thead>
                <tr>
                    <th>OrderId</th>
                    <th>Customer Name</th>
                    <th>Contact No</th>
                    <th>Ordered Item</th>
                    <th>Quantity</th>
                    <th>Sales Agent Name</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="order in Orders">
                    <td>{{order.OrderId}}</td>
                    <td>{{order.CustomerName}}</td>
                    <td>{{order.CustomerMobileNo}}</td>
                    <td>{{order.OrderedItem}}</td>
                    <td>{{order.OrderedQuantity}}</td>
                    <td>{{order.SalesAgentName}}</td>
                </tr>
            </tbody>
        </table>
        <span>{{Message}}</span>
    </div>
    
</div>

In the above markup, we have the following specifications:

  • Bootstraps the Angular application with the module ngmodule and uses the controller ngcontroller defined in Logic.js.
  • The <table> is applied with styles in defined in Bootstrap.
  • The <select> element generates <option> using the JavaScript array of name Selectors declared in Angular controller.
  • The <input> text element is bound with the filterValue scope object declared in the controller. This <input> text is bound with the getFilteredData() function declared in the Controller.
  • The <table> generates <tr> based on the Orders scope object in the controller.

Step 8: To run the Index.cshtml for the OrdersInfo controller, open RouteConfig.cs file in the App_Start folder and make the following changes (highlighted)

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "OrdersInfo", action = "Index", id = UrlParameter.Optional }
        );
    }
}

Run the application, the following output will be displayed:

orders-view

Select the Criteria from the <select> and based on that Enter the Search value in the textbox, the logic will filter records. E.g. Select ‘CustomerName’ from the <select> and enter SRS in the textbox, this will filter records as shown in the following image:

angularjs-search

Likewise we can search based on other criteria like MobileNo, SalesAgentName etc.

Conclusion: The two-way binding system in Angular.js makes the process of building highly responsive applications, much easier. This is one of the several use cases where the combination of Angular.js and ASP.NET Web API play pretty well together. Use the comments section and share your use-cases of mixing these two technologies. Also let me know how was your experience.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!