[AngularJS][ASP Net MVC] 利用ng-form與ng-repeat建立動態表單

利用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)皆為必填資訊,最後只有在驗證無誤才可讓用戶點選儲存鍵來送出資料。

image

首先建立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作用域。

image

 

最後來建立Create View (View/Home/Create.cshtml)。首先需加註ng-controller來規範OrderController的作用區域,再來就使用ng-form搭配ng-repeat來呈現每一筆訂單資訊,並利用ng-messages來顯示資料驗證失敗的文字訊息。新增、移除及儲存訂單Button也利用ng-click來綁定至OrderController相關方法。

image


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

 

最後實際演練一下。 可以看到新增、刪除及資料驗證功能皆正常。

ng-form1

 

按下儲存送出資料後,可於後端接收到完整資訊。實現了我們所預期的功能效果。

image

 

參考資訊

http://www.benlesh.com/2013/03/angular-js-validating-form-elements-in.html


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !