核心要點
ng-required
和ng-pattern
)快速建立客戶端輸入驗證。 FormController
管理表單狀態和驗證,為用戶提供即時反饋,提升用戶體驗。 ng-submit
指令處理AngularJS中的表單提交,阻止默認提交行為,並在將數據發送到服務器之前啟用自定義驗證邏輯。 許多開發者在對用戶提交的數據執行複雜的業務約束時面臨獨特的挑戰。最近,我在GiftCards.com編寫應用程序時,我的團隊也面臨著這樣的挑戰。我們需要找到一種方法,允許我們的客戶在一個視圖中編輯多個產品,每個產品都有自己獨特的驗證規則。
這被證明具有挑戰性,因為它要求我們在HTML源代碼中使用多個<form></form>
標籤,並為每個表單實例維護一個驗證模型。在找到解決方案之前,我們嘗試了許多方法,例如使用ngRepeat
顯示子表單。最終,我們為每種產品類型創建一個指令(每個指令在其視圖中都有一個<form></form>
),並讓指令綁定到其父控制器。這使我們能夠利用Angular的父子表單繼承來確保只有在所有子表單都有效的情況下,父表單才有效。在本教程中,我們將構建一個簡單的產品評論屏幕(突出顯示我們當前應用程序的關鍵組件)。我們將有兩個產品,每個產品都有自己的指令,並且每個產品都有獨特的驗證規則。將有一個簡單的結賬按鈕,它將確保兩個表單都有效。
如果您急於看到它的實際效果,您可以直接跳轉到我們的演示,或從我們的GitHub存儲庫下載代碼。
關於指令
指令是一段HTML代碼,它通過AngularJS的HTML編譯器($compile
)運行,並附加到DOM。編譯器負責遍歷DOM,查找它可以使用其他已註冊指令轉換為對象的組件。指令在一個隔離的作用域內工作,並維護自己的視圖。它們是強大的工具,可以促進可重用的組件,這些組件可以在整個應用程序中共享。要快速復習,請查看這篇文章或AngularJS文檔。
指令以兩種方式解決了我們的根本問題:首先,每個實例都有一個隔離的作用域;其次,指令使用編譯器傳遞,編譯器使用Angular的ngForm
指令識別視圖HTML中的表單元素。這個內置指令允許多個嵌套的表單元素,接受一個可選的name
屬性來實例化FormController
,並將返回表單對象。
關於FormController
當編譯器識別DOM中的任何表單對象時,它將使用ngForm
指令實例化一個FormController
對象。此控制器將掃描所有輸入、選擇和文本區域元素,並創建相應的控件。控件需要一個模型屬性來設置雙向數據綁定,並允許通過各種預構建的驗證方法提供即時用戶反饋。為消費者提供即時反饋,使他們能夠在發出HTTP請求之前知道哪些信息有效。
預構建的驗證方法
Angular打包了14種標準驗證方法。這些包括min
、max
、required
等驗證器。它們被構建為理解和操作幾乎所有HTML5輸入類型,並且與跨瀏覽器兼容。
<input type="text" ng-model="size" ng-required="true" novalidate> <span ng-show="myForm.size.$error.required"> Size: The value is required! </span>
上面的示例顯示了在Angular中使用ngRequired
指令驗證器的用法。此驗證確保在字段被認為有效之前已填寫該字段。它不驗證任何數據,只是用戶是否輸入了某些內容。具有novalidate
屬性表示瀏覽器不應在提交時進行驗證。
專業提示:不要在任何Angular表單上設置
action
屬性。這將阻止Angular嘗試確保表單不會以往返方式提交。
自定義驗證方法
Angular提供了一個廣泛的API來幫助創建自定義驗證規則。使用此API,您可以為標準驗證中未涵蓋的複雜輸入創建和擴展您自己的驗證規則。我的團隊依靠一些自定義驗證方法來運行我們的服務器使用的複雜正則表達式模式。如果沒有運行複雜正則表達式匹配器的能力,我們可能會向後端服務器發送不正確的數據。這將向用戶顯示錯誤,從而導致不良的用戶體驗。自定義驗證器使用指令語法,需要注入ngModel
。更多信息可以通過查閱AngularJS的文檔來找到。
創建控制器
現在,我們可以開始我們的應用程序了。您可以在此處找到控制器代碼的概述。
控制器將是事情的核心。它只有少數幾個職責——它的視圖將有一個名為parentForm
的表單元素,它只有一個屬性,它的方法將包括registerFormScope
、validateChildForm
和checkout
。
控制器屬性
我們需要控制器中的一個屬性:
<input type="text" ng-model="size" ng-required="true" novalidate> <span ng-show="myForm.size.$error.required"> Size: The value is required! </span>
此屬性用於維護表單整體有效性的布爾狀態。我們使用此屬性在單擊“結賬”按鈕後禁用其狀態。
方法:registerFormScope
$scope.formsValid = false;
調用registerFormScope
時,將向其傳遞一個FormController
以及在指令實例化中創建的唯一指令ID。然後,此方法將表單作用域附加到父FormController
。
方法:validateChildForm
此方法將用於與執行驗證的後端服務器協調。當用戶正在編輯內容並且需要進行額外驗證時,將調用它。從概念上講,我們不允許指令執行任何外部通信。
請注意,出於本教程的目的,我省略了後端組件。相反,我根據用戶輸入的金額是否在特定範圍內(產品A為10-50,產品B為25-500),拒絕或解析promise。
$scope.registerFormScope = function (form, id) { $scope.parentForm['childForm'+id] = form; };
使用$q
服務允許指令遵守具有成功和失敗狀態的接口。 “編輯”和“保存”之間的應用程序接口的性質取決於模型數據的編輯。應該注意的是,模型數據在用戶開始鍵入時就會立即更新。
方法:Checkout
單擊“結賬”表示用戶已完成編輯並希望結賬。此可操作項目需要驗證在指令中加載的所有表單都通過驗證,然後才能將模型數據發送到服務器。本文的範圍不包括用於將數據發送到服務器的方法。我鼓勵您探索使用$http
服務進行所有客戶端到服務器的通信。
$scope.validateChildForm = function (form, data, product) { // 重置表单,使其不再有效 $scope.formsValid = false; var deferred = $q.defer(); // 验证表单和数据的逻辑 // 必须在promise上返回resolve()或reject()。 $timeout(function () { if (angular.isUndefined(data.amount)) { return deferred.reject(['amount']); } if ((data.amount < product.minAmount) || (data.amount > product.maxAmount)) { return deferred.reject(['amount']); } deferred.resolve(); }); return deferred.promise; }
此方法使用Angular的能力,子表單可以使父表單無效。父表單名為parentForm
,以清楚地說明其與子表單的關係。當子表單使用其$setValidity
方法時,它將自動上升到父表單以在那裡設置有效性。 parentForm
中的所有表單都必須有效,其內部$valid
屬性才能為true。
創建我們的指令
我們的指令必須遵循一個通用的接口,該接口允許完全互操作性和可擴展性。我們的指令的名稱取決於它們包含的產品。
您可以在此處(產品A)和此處(產品B)找到指令代碼的概述。
隔離指令作用域
每個實例化的指令都將獲得一個隔離的作用域,該作用域被本地化到指令,並且不知道外部屬性。但是,AngularJS允許創建使用父作用域方法和屬性的指令。當將外部屬性傳遞到本地作用域時,您可以指示要設置雙向數據綁定。
我們的應用程序將需要一些外部雙向數據綁定方法和屬性:
$scope.checkout = function () { if($scope.parentForm.$valid) { // 连接服务器以发布数据 } $scope.formsValid = $scope.parentForm.$valid; };
指令本地作用域中的第一個屬性是將本地作用域.form註冊到控制器的方法。指令需要一個管道將本地FormController
對像傳遞給主控制器。
這是將在指令視圖中使用的集中式模型數據。此信息將進行雙向數據綁定,以確保在FormController
中發生的更新將傳播到主控制器。
此方法與控制器中定義的方法相同。當用戶更新指令視圖中的信息時,將調用此方法。
此對象包含有關正在購買的產品的信息。我們的演示使用一個相對較小的對象,只有少數幾個屬性。我的團隊的現實世界應用程序有很多信息用於在應用程序中做出決策。它被傳遞到validateChildForm
中,以提供正在驗證的內容的上下文。
指令鏈接
我們的指令將使用postLink
函數,並向其傳遞一個作用域對象。除此之外,postLink
函數還接受其他幾個參數。它們如下:
scope
– 用於訪問為每個指令實例創建的隔離作用域。 iElement
– 用於訪問元素項。只有在其分配到的元素內,從postLink
函數中更新和修改該元素才是安全的。 iAttrs
– 用於訪問在實例化指令的同一標籤上的屬性。 controller
– 如果存在外部控制器依賴項,則可以在鏈接函數中使用。這些必須與指令對象的require
屬性相對應。 transcludeFn
– 該函數與指令對象的$transclude
參數中列出的函數相同。 link
負責附加所有DOM偵聽器並使用視圖元素更新DOM。
<input type="text" ng-model="size" ng-required="true" novalidate> <span ng-show="myForm.size.$error.required"> Size: The value is required! </span>
$scope.formsValid = false;
將方法registerFormScope
包裝在$timeout
中會將其執行延遲到執行堆棧的末尾。這為編譯器提供了足夠的時間來完成控制器和指令之間的所有必要鏈接。 scope.form.fields
是一個數組,是FormController
中找到的屬性的名稱,這對於設置服務器端驗證錯誤非常重要。 registerFormScope
的目的是將FormController
發送到父控制器,允許新創建的表單設置為parentForm
的子表單。
$scope.registerFormScope = function (form, id) { $scope.parentForm['childForm'+id] = form; };
當表單發生更改並且用戶準備好對其進行驗證時,將調用指令中的saveForm
方法。此方法將依次調用控制器的validateChildForm
方法,並傳入FormController
、scope.giftData
和scope.product
。控制器返回一個promise,該promise將根據其他驗證規則被解析或拒絕。
當promise被拒絕時,控制器將返回無效的字段。這用於使表單(和parentForm
)無效,並設置其他字段級別錯誤。在我們的演示中,我們在amount
字段上使用簡單的後驗證,並且我們不返回失敗的原因。來自validateChildForm
的拒絕可以像您的應用程序需要的那麼複雜或簡單。
當promise成功返回時,指令需要設置表單中字段的有效性。代碼還必須清除任何先前識別的服務器錯誤。這確保指令不會錯誤地向用戶提供錯誤。使用$setValidity
設置所有字段會鏈接到控制器中的parentForm
,以設置其有效性,前提是所有子表單都有效。
設置我們的視圖
視圖不是很複雜,為了我們的演示,我們將產品簡化為以下字段:名稱和金額。在下一步中,我們將探討完成此應用程序所需的視圖。
您可以在此處(產品A)和此處(產品B)找到視圖代碼的概述。
路由視圖
<input type="text" ng-model="size" ng-required="true" novalidate> <span ng-show="myForm.size.$error.required"> Size: The value is required! </span>
此視圖很重要,因為它設置了父表單,該表單將用於包裝從產品指令加載的所有子表單。在ng-repeat
中使用ng-if
可確保不會使用未使用的FormController
錯誤地填充DOM。
指令視圖
$scope.formsValid = false;
注意:上面關於演示佈局的視圖在某些地方已被截斷,與本文無關。
上面的amountInput
設置了一個驗證模式,該模式將由Angular的ngPattern
驗證器強制執行。上面的字段將使用Angular構建的ngDisabled
指令,該指令評估表達式,如果為true,則字段將被禁用。
在視圖底部,我們顯示所有錯誤,以便在用戶單擊“保存”按鈕時向用戶提供反饋。這將設置子表單上的$submitted
屬性。
總結
將所有部分放在一起,我們最終得到以下內容:(此處應插入CodePen鏈接或代碼片段)
您也可以在GitHub上找到所有代碼。
結論
我的團隊在構建我們的最新應用程序時學到了很多東西。了解父子表單關係使我們能夠簡化我們的評論屏幕。使用指令使我們能夠開發一個可以在任何上下文中使用的表單,並促進良好的可重用代碼。指令還使我們能夠進行單元測試代碼,以確保我們的表單按預期工作。我們的應用程序正在生產中,並且已經促成了超過100,000個訂單。
我希望您喜歡閱讀這篇文章。如果您有任何問題或意見,我很樂意在下面的評論中聽到它們。
AngularJS中基於表單的指令的常見問題解答(FAQ)
AngularJS中基於表單的指令在管理和驗證表單中的用戶輸入方面發揮著至關重要的作用。它們提供了一種創建自定義HTML標籤的方法,這些標籤充當新的自定義窗口小部件。它們還可以以向我們的應用程序添加功能的方式來操作DOM。當您希望在整個應用程序中封裝和重用通用功能時,這些指令尤其有用。
在AngularJS中創建自定義基於表單的指令涉及使用.directive
函數定義一個新指令。您需要為您的指令提供一個名稱和一個工廠函數,該函數將生成指令的選項對象。此對象可以定義多個屬性,包括restrict
、template
、scope
、link
等等。 restrict
選項用於指定如何在HTML中調用指令。
AngularJS提供了一些用於表單驗證的內置指令,包括ng-required
、ng-pattern
、ng-minlength
、ng-maxlength
等等。這些指令向您的表單輸入添加了驗證功能,確保用戶輸入在表單提交之前滿足某些條件。您還可以為更複雜的驗證要求創建自定義驗證指令。
AngularJS中的FormController
提供用於跟踪表單及其控件的狀態、檢查有效性和重置表單的方法。它在表單指令內自動可用,可以注入到控制器、其他指令或服務中。
AngularJS中的ng-submit
指令允許您在提交表單時指定自定義行為。您可以使用ng-submit
在事件發生時執行表達式,而不是編寫JavaScript代碼來處理表單的提交事件。這在表單無效時阻止默認表單提交行為時尤其有用。
AngularJS中form
和ng-form
的主要區別在於ng-form
可以嵌套在其他表單中。這允許您將相關的輸入組合在一起並將其作為一個子表單進行驗證。另一方面,標準的form
指令不支持嵌套。
您可以使用ngModelController
提供的$setValidity
方法來設置AngularJS中表單字段的有效性。此方法接受兩個參數:驗證鍵和布爾值。如果布爾值為false,則該鍵將添加到字段的$error
對像中。
AngularJS中的ng-model
指令將輸入、選擇、文本區域或自定義表單控件綁定到作用域上的屬性。它在模型和視圖之間提供雙向數據綁定。這意味著對輸入字段的任何更改都將自動更新模型,反之亦然。
AngularJS中的ng-change
指令允許您在用戶更改輸入時指定自定義行為。當您希望在用戶完成鍵入或進行選擇後立即執行某些操作,而不是等待表單提交時,此指令很有用。
在AngularJS中創建自定義驗證指令涉及定義一個需要ngModel
的新指令。在指令的link
函數中,您可以使用ngModelController
的$validators
或$asyncValidators
管道來添加自定義驗證邏輯。
以上是如何在Angularjs中創建基於表單的指令的詳細內容。更多資訊請關注PHP中文網其他相關文章!