利用ng-form與ng-repeat建立動態表單
前言
在ASP.NET MVC中若是要達到動態新增/移除表單中資料集合項目時,大多都會使用Ajax方式來Append新輸入框Html至畫面上,而此時就必須考慮到ASP .NET MVC資料綁定的機制,好讓新增輸入框Html Element Name依循著MVC資料綁定規則而產出,如此才可在表單送出時於後端接收到完整資料;這部分其實需要使用到一些小技巧來實現,有興趣的朋友可以參考 如何綁定可動態新增或移除之資料集合(EditorTemplate) 文章,裡面有進一步的探討及說明。
相同功能若使用AngularJS來處理的話,簡直就是一塊小蛋糕。我們可以透過ng-form搭配ng-repeat來進行實現,而且在新增表單中資料集合項目時,無須再使用Ajax至後端處理後再將Html送到前端,而是可以完全地在前端進行,此外在資料驗證上也不會有任何問題。以下將用一個簡單的範例進行實作說明。
實作介紹
需求畫面如下,可以動態地新增/移除下方訂單資訊(Order),且具有資料驗證功能。其中每筆訂單的買家(Buyer)與住址(Address)皆為必填資訊,最後只有在驗證無誤才可讓用戶點選儲存鍵來送出資料。
首先建立ViewModel (CreateViewModel.cs),主要就是定義畫面上所需資訊類別。
namespace NgFormWebApp.ViewModel
{
// Create ViewModel
public class CreateViewModel
{
// All Orders
public List<Order> Orders { get; set; }
// SubClass - Order Information
public sealed class Order
{
// 買家
public string Buyer { get; set; }
// 住址
public string Address { get; set; }
}
}
}
建立ASP.NET MVC之Controller (HomeController.cs),只接受POST方式傳遞資料至Create中。
namespace NgFormWebApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(CreateViewModel viewModel)
{
if (ModelState.IsValid)
{
// insert viewModel.Orders to db
}
return View(viewModel);
}
}
}
再來就是處理前端部分
AngularJS - App Module (app.module.js)
由於會使用到ngMessages來處理資料驗證錯誤訊息的顯示工作,因此需要在這邊加入ngMessages模組。
angular
.module('app', ['ngMessages']);
AngularJS - Order Service (order.service.js)
可透過createOrder方法post資料至後端。
angular
.module('app')
.factory("orderService", function ($http, $q) {
return {
// Create Orders
createOrders: function (viewModel) {
// Get the deferred object
var deferred = $q.defer();
// Initiates the AJAX call
$http({ method: 'POST', url: '/Home/Create', data: viewModel })
.success(deferred.resolve).error(deferred.reject);
// Returns the promise - Contains result once request completes
return deferred.promise;
}
}
});
AngularJS - Order Controller (order.controller.js)
將先前所定義的orderService注入至controller中使用,並且建立訂單資訊(orders)變數,以及實作新增、移除及儲存訂單之方法,提供頁面上操作使用。
angular
.module('app')
.controller("OrderController", function (orderService) {
var vm = this;
// set initial orders
vm.orders = [];
vm.orders.push({ Buyer: 'Chris', Address: "Taiwan Taipei ..." });
// add order
vm.addOrder = function () {
vm.orders.push({ Buyer: '', Address: "" });
};
// remove order
vm.removeOrder = function (index) {
vm.orders.splice(index, 1);
};
// save orders
vm.saveOrders = function () {
orderService.createOrders(vm).then(function () {
alert('done');
//window.location.replace('...');
}, function ()
{ alert('error while posting data to server'); })
};
});
在_layout.cshtml中加入所需之JS檔案參考,並設定ng-app作用域。
最後來建立Create View (View/Home/Create.cshtml)。首先需加註ng-controller來規範OrderController的作用區域,再來就使用ng-form搭配ng-repeat來呈現每一筆訂單資訊,並利用ng-messages來顯示資料驗證失敗的文字訊息。新增、移除及儲存訂單Button也利用ng-click來綁定至OrderController相關方法。
<div ng-controller="OrderController as ctrl">
<!-- main form -->
<form name="ordersForm" ng-submit="ctrl.saveOrders()" novalidate>
<input type="button" value="新增" ng-click="ctrl.addOrder()" class="btn" />
<input type="submit" value="儲存" ng-disabled="ordersForm.$invalid" class="btn" />
<br><br>
<!-- sub form - repeat order -->
<ng-form ng-repeat="order in ctrl.orders" name="subForm">
<!-- group box -->
<fieldset class="well the-fieldset">
<legend class="the-legend">Order</legend>
<table width="100%">
<tr>
<td>Buyer</td>
<td>
<!-- Input Buyer -->
<input type="text" name="buyer" ng-model="order.Buyer"
required class="form-control input-sm">
<!-- Input Buyer Validation Msg -->
<span ng-messages="subForm.buyer.$error"
ng-show="subForm.buyer.$dirty"
ng-messages-include="commonMessage">
</span>
</td>
</tr>
<tr>
<td>Address</td>
<td>
<!-- Input Address -->
<input type="text" name="address" ng-model="order.Address"
required class="form-control input-sm">
<!-- Input Address Validation Msg -->
<span ng-messages="subForm.address.$error"
ng-show="subForm.address.$dirty"
ng-messages-include="commonMessage">
</span>
</td>
</tr>
<tr>
<!-- Remove Button -->
<td>
<input type="button" value="移除"
ng-click="ctrl.removeOrder($index)" class="btn" />
</td>
<td> </td>
</tr>
</table>
</fieldset>
</ng-form>
</form>
<br>
</div>
<!-- 定義共用的錯誤訊息(可抽出為獨立檔案) -->
<script type="text/ng-template" id="commonMessage">
<span ng-message="required" class="text-danger field-validation-error">Required</span>
</script>
最後實際演練一下。 可以看到新增、刪除及資料驗證功能皆正常。
按下儲存送出資料後,可於後端接收到完整資訊。實現了我們所預期的功能效果。
參考資訊
http://www.benlesh.com/2013/03/angular-js-validating-form-elements-in.html
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !