原文地址:http://www.codeproject.com/Articles/808213/Developing-a-Large-Scale-Application-with-a-Single
AngularUI
下面的示例中使用了AngularUI的各種UI元件。AngularUI 是AngularJS 框架的一個輔助套件。示例中使用的主要元件大部分來在AngularUI 的一個子集UI Bootstrap。UI Bootstrap是從Twitter Bootstrap派生出來的,它使用AngularJS編碼實現。 UI Bootstrap庫包含了一套使用Bootstrap標識和樣式的AngularJS 指令。 這使得它不依賴jQuery.js和Bootstrap.js。
Alert (ui.bootstrap.alert)
AngularJS Alert 是由Bootstrap alert 派生過來的。 使用ng-repeat指令,可以實現動態彈窗提示模型裡的資料問題。
<div style="padding-top:20px"> <alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)"> <div ng-bind-html="MessageBox"></div> </alert> </div>
為了更好的擴充警告指令, 這個示例應用程式包含了一個自定義的指令服務(custom alerts service).它可以在整個應用程式中使用,以渲染警告資訊.資訊的內容設定在$rootScope裡面,它來自於伺服器的業務層的驗證過程,並在AJAX請求完成後渲染到客戶端.
// alertsService.js define(['application-configuration'], function (app) { app.register.service('alertsService', ['$rootScope', function ($rootScope) { $rootScope.alerts = []; $rootScope.MessageBox = ""; this.SetValidationErrors = function (scope, validationErrors) { for (var prop in validationErrors) { var property = prop + "InputError"; scope[property] = true; } } this.RenderErrorMessage = function (message) { var messageBox = formatMessage(message); $rootScope.alerts = []; $rootScope.MessageBox = messageBox; $rootScope.alerts.push({ 'type': 'danger', 'msg': '' }); }; this.RenderSuccessMessage = function (message) { var messageBox = formatMessage(message); $rootScope.alerts = []; $rootScope.MessageBox = messageBox; $rootScope.alerts.push({ 'type': 'success', 'msg': '' }); }; this.RenderWarningMessage = function (message) { var messageBox = formatMessage(message); $rootScope.alerts = []; $rootScope.MessageBox = messageBox; $rootScope.alerts.push({ 'type': 'warning', 'msg': '' }); }; this.RenderInformationalMessage = function (message) { var messageBox = formatMessage(message); $rootScope.alerts = []; $rootScope.MessageBox = messageBox; $rootScope.alerts.push({ 'type': 'info', 'msg': '' }); }; this.closeAlert = function (index) { $rootScope.alerts.splice(index, 1); }; function formatMessage(message) { var messageBox = ""; if (angular.isArray(message) == true) { for (var i = 0; i < message.length; i++) { messageBox = messageBox + message[i]; } } else { messageBox = message; } return messageBox; } }]); });
當新增一個客戶記錄出錯時,下面的程式碼被執行,同時呼叫警告服務.
$scope.createCustomerError = function (response) { alertsService.RenderErrorMessage(response.ReturnMessage); $scope.clearValidationErrors(); alertsService.SetValidationErrors($scope, response.ValidationErrors); }
Datepicker控制元件 (ui.bootstrap.datepicker)
UI Bootstrap Datepicker控制元件 是一種清潔、靈活和完全可定製的日期選擇器。
把Datepicker相關的引數新增到輸入框,然後新增一個按鈕,使用者可以通過單擊日曆圖示顯示Datepicker。
<tr> <td class="input-label" align="right"><label class="required">Required Ship Date:</label></td> <td class="input-box" style="height:50px"> <div ng-bind="RequiredDate" ng-show="DisplayMode"></div> <div ng-show="EditMode"> <div class="row"> <div class="col-md-6"> <p class="input-group"> <input ng-class="{'validation-error': RequiredDateInputError}" type="text" style="width:100px" datepicker-popup="MM/dd/yyyy" ng-model="RequiredDate" is-open="opened" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" /> <button type="button" ng-click="open($event)"><i style="height:10px" class="glyphicon glyphicon-calendar"></i></button> </p> </div> </div> </div> </td> </tr>
Modal (ui.bootstrap.modal)
UI Bootstrap的Modal是一種服務,它可以快速的建立擁有Angular屬性的模態對話方塊.建立定製化的modal是很簡單,只需建立部分檢視,增加一個控制器,然後在使用服務的時候引用它們.
下面的JavaScript程式碼為Product Inquiry Modal開啟了一個HTML模板,並建立了一個modal例項.當一個產品專案被選中的時候,產品id通過modal例項的結果方法返回.這個modal例項從伺服器獲取產品資訊.產品資訊返回到呼叫頁面後,modal消失.
$scope.openModal = function () { var modalInstance = $modal.open({ templateUrl: 'productLookupModal.html', controller: ModalInstanceCtrl, windowClass: 'app-modal-window' }); modalInstance.result.then(function (productID) { var getProduct = new Object(); getProduct.ProductID = productID; productService.getProduct(getProduct, $scope.getProductCompleted, $scope.getProductError); }, function () { // function executed on modal dismissal }); }; var ModalInstanceCtrl = function ($scope, $modalInstance) { $scope.ProductCode = ""; $scope.ProductDescription = ""; $scope.productSelected = function (productID) { $modalInstance.close(productID); }; $scope.cancel = function () { $modalInstance.dismiss('cancel'); }; };
Typeahead (ui.bootstrap.typeahead)
Typeahead是AngularJS Bootstrap v2版本的typeahead外掛.這個指令可以快速建立一個漂亮的基於任意文字框的typeahead控制元件.Product Inquiry Modal視窗使用了Typeahead指令
<input type="text" ng-model="Description" typeahead="product for products in getProducts($viewValue)">
在上面例子中的typeahead指令,將把輸入框中的輸入資訊作為引數並執行getProducts函式.然後getProducts函式會呼叫Products Service來執行一個AJAX請求.這個請求將返回一個基於使用者輸入資訊的產品資料的頁面,並設定產品查詢資料列表.
$scope.getProducts = function () { var productInquiry = $scope.createProductInquiryObject(); productService.getProducts(productInquiry, $scope.productInquiryCompleted, $scope.productInquiryError); }
Pagination (ui.bootstrap.pagination)
Pagination是一個輕量級的分頁指令,它可以提供資料列表分頁,顯示分頁欄以及正確啟用和禁用翻頁按鈕.
<pagination boundary-links="true" total-items="TotalProducts" items-per-page="PageSize" ng-change="pageChanged()" ng-model="CurrentPageNumber" class="pagination-lg" previous-text="Prev" next-text="Next" first-text="First" last-text="Last"></pagination>
這個應用程式的所有的資料列表都使用了UI Bootstrap分頁控制元件.實際上,有了HTML模板和資料繫結功能,實現多用途的資料列表是很容易的.這個資料列表包含類似於這個應用程式的分頁和排序功能.
下面的產品查詢資料列表的HTML模板,詳細描述瞭如何使用檢視來排序以及分頁.在控制器的檢視模型中的資料是和表格繫結,其中表格的行是通過AngularJS的ng-repeat指令動態渲染的.這個指令也用於動態建立表頭.使用者可以通過點選表頭來排序.HTML模板和資料繫結功能提供了強大的和簡潔的動態生成功能.使用一段時間的HTML模板後,你將不願再回到使用ASP.NET控制元件的一團糟的狀況了.
<!-- productLookupModal.html --> <table class="table table-striped table-hover" style="width: 100%;"> <thead> <tr> <th colspan="2" style="width: 50%"> <span ng-bind="TotalProducts"></span> Products </th> <th colspan="5" style="text-align: right; width: 50%"> Page <span ng-bind="CurrentPageNumber"></span> of <span ng-bind="TotalPages"></span> </th> </tr> <tr> <th ng:repeat="tableHeader in tableHeaders" ng:class="setSortIndicator(tableHeader.label)" ng:click="changeSorting(tableHeader.label)">{{tableHeader.label}}</th> </tr> </thead> <tbody> <tr ng-repeat="product in products"> <td style="width: 25%; height: 25px"><a ng-click="ok(product.ProductID)" style=" cursor pointer; text-decoration underline; color black">{{product.ProductCode}}</a></td> <td style="width: 50%; white-space: nowrap"><div ng-bind="product.Description"></div></td> <td style="width: 25%; text-align:left; white-space: nowrap"> <div>{{product.UnitPrice | currency}}</diV></td> </tr> </tbody> </table> <pagination boundary-links="true" total-items="TotalProducts" items-per-page="PageSize" ng-change="pageChanged()" ng-model="CurrentPageNumber" class="pagination-lg" previous-text="Prev" next-text="Next" first-text="First" last-text="Last"> </pagination>
最後,包裝一下產品查詢列表,下面的產品查詢模態控制器包含了一個自定義資料列表服務引用.它用來在示例應用程式中,為所有的資料列表實現排序功能.這是又一個使用AngularJS Services和Factories的例子.它把程式碼封裝成小的可重複使用的,簡潔的,易讀的和易於維護的模組.
// productLookupModalController.js "use strict"; define(['application-configuration', 'productsService', 'alertsService', 'dataGridService'], function (app) { app.register.controller('productLookupModalController', ['$scope', '$rootScope', 'productsService', 'alertsService', 'dataGridService', function ($scope, $rootScope, productService, alertsService, dataGridService) { $scope.initializeController = function () { $rootScope.alerts = []; dataGridService.initializeTableHeaders(); dataGridService.addHeader("Product Code", "ProductCode"); dataGridService.addHeader("Product Description", "Description"); dataGridService.addHeader("Unit Price", "UnitPrice"); $scope.tableHeaders = dataGridService.setTableHeaders(); $scope.defaultSort = dataGridService.setDefaultSort("Description"); $scope.changeSorting = function (column) { dataGridService.changeSorting( column, $scope.defaultSort, $scope.tableHeaders); $scope.defaultSort = dataGridService.getSort(); $scope.SortDirection = dataGridService.getSortDirection(); $scope.SortExpression = dataGridService.getSortExpression(); $scope.CurrentPageNumber = 1; $scope.getProducts(); }; $scope.setSortIndicator = function (column) { return dataGridService.setSortIndicator(column, $scope.defaultSort); }; $scope.ProductCode = ""; $scope.Description = ""; $scope.PageSize = 5; $scope.SortDirection = "ASC"; $scope.SortExpression = "Description"; $scope.CurrentPageNumber = 1; $rootScope.closeAlert = dataGridService.closeAlert; $scope.products = []; $scope.getProducts(); } $scope.productInquiryCompleted = function (response, status) { alertsService.RenderSuccessMessage(response.ReturnMessage); $scope.products = response.Products; $scope.TotalProducts = response.TotalRows; $scope.TotalPages = response.TotalPages; } $scope.searchProducts = function () { $scope.CurrentPageNumber = 1; $scope.getProducts(); } $scope.pageChanged = function () { $scope.getProducts(); } $scope.getProducts = function () { var productInquiry = $scope.createProductInquiryObject(); productService.getProducts(productInquiry( $scope.productInquiryCompleted, $scope.productInquiryError); } $scope.getProductsTypeAheadProductCode = function (productCode) { $scope.ProductCode = productCode; var productInquiry = $scope.createProductInquiryObject(); productService.getProductsWithNoBlock(productInquiry, $scope.productInquiryCompleted, $scope.productInquiryError); } $scope.getProductsTypeAheadDescription = function (description) { $scope.Description = description; var productInquiry = $scope.createProductInquiryObject(); productService.getProductsWithNoBlock(productInquiry, $scope.productInquiryCompleted, $scope.productInquiryError); } $scope.productInquiryError = function (response, status) { alertsService.RenderErrorMessage(response.Error); } $scope.resetSearchFields = function () { $scope.ProductCode = ""; $scope.Description = ""; $scope.getProducts(); } $scope.createProductInquiryObject = function () { var productInquiry = new Object(); productInquiry.ProductCode = $scope.ProductCode; productInquiry.Description = $scope.Description; productInquiry.CurrentPageNumber = $scope.CurrentPageNumber; productInquiry.SortExpression = $scope.SortExpression; productInquiry.SortDirection = $scope.SortDirection; productInquiry.PageSize = $scope.PageSize; return productInquiry; } $scope.setHeaderAlignment = function (label) { if (label == "Unit Price") return { 'textAlign': 'right' } else return { 'textAlign': 'left' } } }]); });
結論
我敢說jQuery過時了嗎?當然,jQuery仍然很流行並廣泛使用.但是,過去的一些年見證了結構化設計模式的框架和庫,如MVC和MVVM(Model-View-ViewModel)的崛起.這些框架和庫包括Backbone.js, Ember.js和AngularJS等.
AngularJS是一個MVC/MVVM framework.它由google建立,以開發具有良好體系結構的和可維護的web應用程式.AngularJS定義了大量的概念來合理的組織web應用程式.應用程式由相互依賴的模組來定義.它通過新的屬性或者標籤和表示式,關聯指令到頁面來增強HTML,以定義功能強大的模板.它也將應用程式的行為封裝到控制器,這些控制器通過依賴注入的方式例項化.這有利於結構化,而且非常容易測試JavaScript程式碼.是的,這裡有你開發大型應用程式前端程式碼所需的所有東西.AngularJS可能是自jQuery之後,下一個JavaScript大事件.
建立示例應用程式所用到的技術
AngularJS
RequireJS
Visual Studio Express 2013 for Web
Microsoft .NET 4.5.1
Microsoft .NET C#
Microsoft Web API 2
Microsoft Entity Framework 6.0
SQL Server Express
完~~~