Home >Web Front-end >JS Tutorial >How to Create Form-Based Directives in AngularJS

How to Create Form-Based Directives in AngularJS

Joseph Gordon-Levitt
Joseph Gordon-LevittOriginal
2025-02-19 11:52:13925browse

How to Create Form-Based Directives in AngularJS

Core points

  • Create reusable form components using AngularJS directives. The components have independent scopes, enhancing the modularity and maintainability of web applications.
  • Implement custom verification methods in directives to handle complex input verification, ensuring data integrity before being submitted to the server.
  • Use AngularJS built-in form verification technologies (such as ng-required and ng-pattern) to quickly establish client input verification.
  • Use FormController in AngularJS to manage form status and verification to provide users with instant feedback and improve user experience.
  • Use the ng-submit directive to handle form submissions in AngularJS, blocking the default submission behavior, and enabling custom verification logic before sending data to the server.

Many developers face unique challenges when executing complex business constraints on user-submitted data. Recently, my team faced this challenge when I was writing an application at GiftCards.com. We need to find a way to allow our customers to edit multiple products in one view, each with its own unique verification rules.

This proves challenging because it requires us to use multiple <form></form> tags in the HTML source code and maintain a validation model for each form instance. Before we find the solution, we tried many methods, such as using ngRepeat to display subforms. Finally, we create a directive for each product type (each directive has a <form></form> in its view) and have the directive bind to its parent controller. This allows us to leverage Angular's parent-child form inheritance to ensure that the parent form is valid only if all child forms are valid. In this tutorial, we will build a simple product review screen (highlighting the key components of our current application). We will have two products, each with its own instructions and each product has unique verification rules. There will be a simple checkout button, which will ensure both forms are valid.

If you are anxious to see how it actually works, you can jump directly to our demo or download the code from our GitHub repository.

About the command

The

directive is a piece of HTML code that runs through AngularJS's HTML compiler ($compile) and is attached to the DOM. The compiler is responsible for traversing the DOM and finding components that it can convert into objects using other registered directives. Directives work within an isolated scope and maintain their own views. They are powerful tools that facilitate reusable components that can be shared throughout the application. For a quick review, check out this article or AngularJS documentation.

The

directive solves our fundamental problem in two ways: first, each instance has an isolated scope; second, the directive is passed using the compiler, which uses the Angular ngForm directive to recognize the Form element. This built-in directive allows multiple nested form elements to accept an optional name attribute to instantiate FormController and will return the form object.

About FormController

When the compiler recognizes any form object in the DOM, it will instantiate a ngForm object using the FormController directive. This controller will scan all input, selection, and text area elements and create corresponding controls. The control requires a model property to set up two-way data binding and allows instant user feedback through various pre-built verification methods. Provide instant feedback to consumers, allowing them to know what information is valid before making HTTP requests.

Prebuilt verification method

Angular packages 14 standard verification methods. These include min, max, required and other validators. They are built to understand and manipulate almost all HTML5 input types and are cross-browser-compatible.

<code class="language-html"><input type="text" ng-model="size" ng-required="true" novalidate>
  <span ng-show="myForm.size.$error.required">
    Size:
    The value is required!
  </span></code>

The above example shows how to use the ngRequired directive validator in Angular. This verification ensures that the field is filled in before it is considered valid. It does not verify any data, it just does the user enter something. Having the novalidate attribute means that the browser should not verify when submitting.

Pro tip: Do not set action attributes on any Angular form. This will prevent Angular from trying to make sure the form is not submitted in a round trip manner.

Custom verification method

Angular provides an extensive API to help create custom validation rules. With this API, you can create and extend your own validation rules for complex inputs not covered in standard validation. My team relies on some custom validation methods to run the complex regular expression patterns our server uses. Without the ability to run a complex regular expression matcher, we may send incorrect data to the backend server. This will show errors to the user, resulting in a bad user experience. Custom validators use directive syntax and need to be injected ngModel. More information can be found by consulting the AngularJS documentation.

Create the controller

Now, we can start our application. You can find an overview of the controller code here.

The controller will be at the heart of things. It has only a few responsibilities - its view will have a form element named parentForm, it has only one attribute, and its methods will include registerFormScope, validateChildForm and checkout.

Controller properties

We need a property in the controller:

<code class="language-html"><input type="text" ng-model="size" ng-required="true" novalidate>
  <span ng-show="myForm.size.$error.required">
    Size:
    The value is required!
  </span></code>

This property is used to maintain the Boolean state of the overall validity of the form. We use this property to disable its status after clicking the Checkout button.

Method: registerFormScope

<code class="language-javascript">$scope.formsValid = false;</code>
When

is called, a registerFormScope and a unique directive ID created in the instruction instantiation are passed to it. This method then appends the form scope to the parent FormController. FormController

Method: validateChildForm

This method will be used to coordinate with the backend server that performs the verification. It is called when the user is editing the content and needs additional verification. Conceptually, we do not allow instructions to perform any external communication.

Please note that for the purposes of this tutorial, I omitted the backend components. Instead, I reject or parse promises based on whether the amount entered by the user is within a specific range (product A is 10-50 and product B is 25-500).

<code class="language-javascript">$scope.registerFormScope = function (form, id) {
  $scope.parentForm['childForm'+id] = form;
};</code>
Using the

service allows instructions to comply with interfaces with success and failure status. The nature of the application interface between "Edit" and "Save" depends on the editing of the model data. It should be noted that the model data is updated immediately when the user starts typing. $q

Method: Checkout

Click "Checkout" to indicate that the user has completed editing and wants to checkout. This actionable item requires verification that all forms loaded in the directive are validated before the model data can be sent to the server. The scope of this article does not include methods for sending data to a server. I encourage you to explore using the

service for all client-to-server communication. $http

<code class="language-javascript">$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;
}</code>
This method uses Angular's ability, and child forms can invalidate the parent form. The parent form is named

to clearly illustrate its relationship with the child form. When the child form uses its parentForm method, it will automatically rise to the parent form to set validity there. All forms in $setValidity must be valid, and their internal parentForm attributes must be true. $valid

Create our directive

Our instructions must follow a common interface that allows for full interoperability and scalability. The name of our directives depends on the product they contain.

You can find an overview of the instruction code here (product A) and here (product B).

Scope of the isolation instruction

Each instantiated directive will get an isolated scope that is localized to the directive and has no external properties known. However, AngularJS allows the creation of directives that use parent scope methods and properties. When passing external properties to the local scope, you can indicate that you want to set up a two-way data binding.

Our application will require some external two-way data binding methods and properties:

<code class="language-javascript">$scope.checkout = function () {
  if($scope.parentForm.$valid) {
    // 连接服务器以发布数据
  }
  $scope.formsValid = $scope.parentForm.$valid;
};</code>
Method: registerFormScope

The first property in the directive local scope is the method to register the local scope.form to the controller. The instruction requires a pipeline to pass the local

object to the main controller. FormController

Object: giftData

This is the centralized model data that will be used in the instruction view. This information will be bidirectional data binding to ensure that updates occurring in FormController will propagate to the main controller.

Method: validateChildForm

This method is the same as the one defined in the controller. This method is called when the user updates information in the instruction view.

Object: product

This object contains information about the product being purchased. Our demonstration uses a relatively small object with only a few properties. My team's real-world application has a lot of information to make decisions in the application. It is passed into validateChildForm to provide the context of the content being verified.

Instruction link

Our directive will use the postLink function and pass it a scope object. In addition, the postLink function also accepts several other parameters. They are as follows:

  1. scope – Used to access the isolation scope created for each directive instance.
  2. iElement – Used to access element items. It is safe to update and modify the element from the postLink function within the element it is allocated to.
  3. iAttrs – Used to access properties on the same tag of the instantiation directive.
  4. controller – If an external controller dependency exists, it can be used in a link function. These must correspond to the require attribute of the directive object.
  5. transcludeFn – This function is the same as the function listed in the $transclude parameter of the instruction object.

link Responsible for attaching all DOM listeners and updating the DOM with view elements.

<code class="language-html"><input type="text" ng-model="size" ng-required="true" novalidate>
  <span ng-show="myForm.size.$error.required">
    Size:
    The value is required!
  </span></code>

Register form scope

<code class="language-javascript">$scope.formsValid = false;</code>

Wrapping method registerFormScope in $timeout will delay its execution until the end of the execution stack. This provides the compiler with enough time to complete all the necessary links between the controller and the instructions. scope.form.fields is an array, the name of the property found in FormController, which is very important for setting up server-side verification errors. The purpose of registerFormScope is to send FormController to the parent controller, allowing the newly created form to be set to a child form of parentForm.

When verification information changes

<code class="language-javascript">$scope.registerFormScope = function (form, id) {
  $scope.parentForm['childForm'+id] = form;
};</code>

When the form changes and the user is ready to verify it, the saveForm method in the directive is called. This method will invoke the controller's validateChildForm method in turn and pass in FormController, scope.giftData and scope.product. The controller returns a promise that will be parsed or rejected according to other validation rules.

When promise is rejected, the controller will return an invalid field. This is used to invalidate the form (and parentForm) and set other field level errors. In our demo, we use simple post-verification on the amount field and we do not return the cause of failure. Rejections from validateChildForm can be as complex or simple as your application needs to.

When promise returns successfully, the command needs to set the validity of the fields in the form. The code must also clear any previously identified server errors. This ensures that the directive does not provide errors to the user incorrectly. Setting all fields with $setValidity will be linked to parentForm in the controller to set their validity, provided that all subforms are valid.

Set our view

The view is not very complicated, and for our demonstration we simplified the product to the following fields: name and amount. In the next step, we will explore the views you need to complete this application.

You can find an overview of the view code here (Product A) and here (Product B).

Route View

<code class="language-html"><input type="text" ng-model="size" ng-required="true" novalidate>
  <span ng-show="myForm.size.$error.required">
    Size:
    The value is required!
  </span></code>

This view is important because it sets up the parent form, which will be used to wrap all child forms loaded from the product directive. Using ng-repeat in ng-if ensures that the DOM is not filled incorrectly with an unused FormController.

Instruction View

<code class="language-javascript">$scope.formsValid = false;</code>

Note: The above view on the demo layout has been truncated in some places and has nothing to do with this article.

The above amountInput sets a verification mode which will be enforced by Angular's ngPattern validator. The above field will use the ngDisabled directive built by Angular, which evaluates the expression, and if true, the field will be disabled.

At the bottom of the view, we display all errors to provide feedback to the user when the user clicks the "Save" button. This will set the $submitted property on the subform.

Summary

Put all the pieces together and we end up with the following: (CodePen link or code snippet should be inserted here)

You can also find all the code on GitHub.

Conclusion

My team learned a lot when building our latest apps. Understanding the father-son form relationship allows us to simplify our comment screen. Using directives allows us to develop a form that can be used in any context and promotes good reusable code. The directive also enables us to unit test the code to ensure our form works as expected. Our application is in production and has contributed to over 100,000 orders.

I hope you enjoyed reading this article. If you have any questions or comments, I'd love to hear them in the comments below.

FAQ for Form-Based Directives in AngularJS

What is the role of form-based directives in AngularJS?

Form-based directives in AngularJS play a crucial role in managing and validating user input in forms. They provide a way to create custom HTML tags that act as new custom widgets. They can also manipulate DOMs in a way that adds functionality to our applications. These instructions are especially useful when you want to encapsulate and reuse common features throughout your application.

How to create custom form-based directives in AngularJS?

Creating a custom form-based directive in AngularJS involves defining a new directive using the .directive function. You need to provide your directive with a name and a factory function that will generate the option object of the directive. This object can define multiple properties, including restrict, template, scope, link, and so on. The restrict option is used to specify how directives are called in HTML.

How to verify form input using AngularJS directive?

AngularJS provides some built-in instructions for form validation, including ng-required, ng-pattern, ng-minlength, ng-maxlength, and more. These instructions add validation to your form input, ensuring that user input meets certain criteria before the form is submitted. You can also create custom verification directives for more complex verification requirements.

What is the purpose of FormController in AngularJS?

FormController in AngularJS provides methods for tracking the status of forms and their controls, checking validity, and resetting forms. It is automatically available within the form directive and can be injected into the controller, other directives, or services.

How to use ng-submit directive in AngularJS?

The

directive in AngularJS allows you to specify custom behavior when submitting a form. Instead of writing JavaScript code to handle the form's submission event using ng-submit. This is especially useful when preventing the default form submission behavior when the form is invalid. ng-submit

What is the difference between form and ng-form in AngularJS?

The main difference between

and

in form in ng-form is that ng-form can be nested in other forms. This allows you to group relevant inputs together and validate them as a subform. On the other hand, the standard form directives do not support nesting.

How to set the validity of a form field in AngularJS?

You can set the validity of form fields in AngularJS using the ngModelController method provided by $setValidity. This method accepts two parameters: the validation key and the boolean value. If the boolean value is false, the key is added to the field's $error object.

How to use ng-model directive in AngularJS form?

The ng-model directive in AngularJS binds input, selection, text area, or custom form control to properties on scope. It provides two-way data binding between the model and the view. This means that any changes to the input field will automatically update the model and vice versa.

What is the role of the ng-change directive in AngularJS form?

The

directive in AngularJS allows you to specify custom behavior when the user changes input. This directive is useful when you want to perform something immediately after the user has finished typing or making a selection instead of waiting for the form to be submitted. ng-change

How to create custom verification directives in AngularJS?

Creating a custom verification directive in AngularJS involves defining a new directive that needs

. In the ngModel function of the directive, you can use the link or ngModelController pipeline to add custom validation logic. $validators

The above is the detailed content of How to Create Form-Based Directives in AngularJS. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn