ایجاد SPA با AngularJS در NET.

در این مقاله نحوه درج اطلاعات در دیتابیس و بازیابی آنها را با Angularjs شرح می دهیم .همراه آن پروژه ای خواهیم نوشت که یک پروژه SPA با استفاده از فرم ورک Angularjs است .

ایجاد SPA با AngularJS در NET.

SPA مخفف Single Page Application میباشد ، این نوع از اپلیکیشن ها گزینه مناسبی برای آموزش CRUD (چهار عمل اصلی)می باشد.

امروزه کاربران خواهان برنامه های تحت وب سریعتر و دسترسی به Application  ها با موبایل و تبلت و .... هستند  . با کمک HTML5, JQuery و  AJAX ایجاد برنامه های SPA امکان پذیر شده است.

SPA واقعا چیست ؟

در واقع یک اپلیکیشن تحت وب چند صفحه ای است که یک صفحه والد و چندین صفحه فرزند دارد که این صفحات فرزند در مواقعی که درخواست شوند اجرا شده و بارگذاری می شوند.در SPA تمام منابع لازم زمانی لود می شوند که درخواست شده باشند و وقتی منابع آزاد می شوند که برای آنها درخواستی وجود داشته باشد.

SPA سعی بر این دارد که حس یک برنامه دسکتاپ را برای کاربر ایجاد کند

SPA در مقایسه با اپلیکیشن های تحت وب سنتی

در یک اپلیکیشن تحت وب سنتی همانطور که در شکل زیر می بینید بعد از اینکه کاربر درخواستی مبنی بر مشاده یک صفحه یا اجرای یک دستور ارسال می کند، این درخواست به سرور ارسال شده و صفحه رندر شده و Html معادل آن به کلاینت بر می گردد.

در SPA زمانی که User درخواستی برای یک صفحه دارد این صفحه به صورت دینامیک لود می شود و یک سری توابع و رویدادها در همین سمت کلاینت انجام می شود .این فراخوانی توسط Ajax  انجام می شود و دیتا توسط Json فراخوانی شده و از سرور بازیابی می شود.این عملکرد SPA  به شما حس یک برنامه دسکتاپ را می دهد.

امتیازات SPA

مسیریابی و رندر دیتا در سمت کلاینت انجام می شود

دیتاها سمت سرور در فرمت Json  هستند

در این پروژه از ویژوال 2013 با .NET 4.5  و همچنین دیتابیس .mdf وbootstrap ، Jquery  استفاده شده است .

به صورت مرحله به مرحله این پروژه را شرح می دهیم

یک پروژه MVC  با Visual Studio 2013  ایجاد کنید

افزودن AngularJS  و Jquery  

در شکل زیر Jquery   و AngularJS  وBootStrap به پروژه اضافه شده است .همچنین در داخل Script  یک پوشه دیگر به نام App  افزوده و داخل آن myapp.js  را اضافه کرده ایم .

در این مرحله فایل های قبل را باید به صورت زیر به پروژه اضافه کنید.

حال باید مطمئن شوید که این فایل ها به مسترپیج (_layout.cshtml)شما افزوده شده است .همانطور که در شکل زیر می بینید

این فایل ها به هدر صفحه مسترپیج شما اضافه شده اند.برای اینکه مطمئن شوید این فایل ها به درستی اضافه شده اند پروژه را اجرا کنید با زدن F12  پنجره firebug در پایین مرورگر باز می شود.تب script  را بزنید.اگر در قسمت Errore  خطایی مشاهده نکنید همه چیز مرتب است!

5-راه اندازی دیتا بیس

در اینجا قصد داریم یک دیتابیس Angular.mdf  که در فولدر App.data وجود دارد ایجاد کنیم.در این دیتابیس دو جدول به نام های   EmpDetails و EmpAddressوجود دارد. EmpDetails اطلاعات مربوط به کارمندان را ذخیره می کندو EmpAddress آدرس مربوط به کارمندان را نگه داری میکند.بین این دو جدول یک کلید خارجی Empid در نظر گرفته ایم .

اسکریپت این دو جدول به شکل زیر است .

EmpDetails جدول

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 جدول

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])
);
namespace SinglePageAngularJS.Models
{
    public class EmpDetailsModel
    {
        public int EmpID { get; set; }
        [DisplayName("نام پرسنل")]
        public string EmpName { get; set; }
        [DisplayName("تلفن")]
        public string EmpPhone { get; set; }
    }
}

کلاسی دیگر تحت نام EmpAddressmodel ایجاد می کنیم . این کلاس معادل جدول EmpAddress است کد آن را در زیر مشاهده می کنید.

 public class EmpAddressModel
    {
        public int EmpAddressId { get; set; }
        [DisplayName("آدرس1")]
        public string Address1 { get; set; }
        [DisplayName("آدرس 2")]
        public string Address2 { get; set; }
        [DisplayName("آدرس 3")]
        public string Address3 { get; set; }
        [DisplayName("شماره پرسنلی")]
        public int EmpID { get; set; }
    }
   public class EmployeeViewModel
    {
        public EmpDetailsModel empDetailModel { get; set; }
        public EmpAddressModel empAddressModel { get; set; }
    }

کد مربوط به Angularjs

در پوشه Script  و در داخل فایل myapp.js کد های مربوط به Angularjs وجود دارند

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";
});
Ng-appدادن نام به app هاست.ng-controller امکان انتخاب یک عنصر به خصوص از app  را می دهد.ng-model مدل و ویو را بایند می کند

Ng-app  نشان میدهد که یک صفحه از نوع Angularjs  داریم.اگر این کد را به تگ Html  اضافه نکینم برنامه به درستی کار نمی کند.زیرا قادر به شناسایی سایر دستورات Angularjs نیست.

مسیریابی سمت کاربر

ما برای Angularjs خود نام app  را داده ایم.و آرایه ای از وابسته های آن را ذکر کرده ایم.

angular.module('App', ['AngularDemo.EmpAddController',

                       'AngularDemo.AddressController',

                       'AngularDemo.DeleteController'

])

حال زمان آن است که مسیریابی سمت کاربر را بنویسیم.در زیر کد مربوط به این کار آورده شده است.همانطور که می بینید با کمک Templateurl و  controller  سه مسیر ایجاد کرده ایم.

.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('!');

}]);

هر زمانی که Angularjs ، url ایی را پیدا می کند که در مسیریابی برای آن تعریف شده است آن را با controller angularjs مطابقت می دهد در زیر کد مربوط به کنترلر آورده شده است.

//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");
            }
        });
    };
});
مسئول تنظیم خصوصیت های مدل و فانکشن های یک کنترل خاص است .در کنترلر EmpAdd ما دو مدل EmpDetailsModel, EmpAddressModel و ویو مدل را داریم .در ویو مدل که آن را به سرور پاس میدهیم و اطلاعات را درون سرور ذخیره می کنیم از فانکشن $scope.AddEmployee استفاده می کنیم و همچنین از $http.get استفاده می کنیم تا اطلاعات را از دیتابیس فراخوانی کنیم.

ساختار صفحه مسترپیج به شکل زیر است.

<!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

یک صفحه با نام Index بسازید و کدهای زیر را در آن کپی کنید.Ng-view یک place holder است که Partial view به صورت اتوماتیک لود می شود.

صفحه addEmployee.html

این صفحه یک Partial view  است با کد زیر:

<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>
در این صفحه کاربر میتواند کارمند اضافه کند و همجنین لیست آنها را ببیند.ng-model در واقع مقادیر کنترل های Html مانند (input, select, textarea) را با دیتاهای اپلیکیشن bind  می کند

صفحه خروجی

با زدن F5  برنامه را اجرا کنید.صفحه ای مانند زیر می بینید .البته این عکس بعد از افزودن چند رکورد گرفته شده است.

با زدن دکمه ذخیره فانکشن   AddEmployee در Angularjs  اجرا می شود. که این فانکشن به نوبه خود یک controller action را به اجرا در می آورد.

یا Single Page Application نسبت به برنامه های تحت شبکه سنتی از کارایی بهتری برخوردار است .اما در مورد امنیت هرگز سازش نکنید ، وقتی بحث امنیت می شود قبل از ایجاد SPA کاملا به آن فکر کنید و تمام جوانب را خوب بسنجید.

فایل های ضمیمه