UNIT 5-FORMS AND ROUTING IN ANGULAR 4.
Template-driven Forms in Angular
Angular's template-driven forms, one of two form-building methods, simplify
complex form management using Angular's two-way data binding. Unlike
model-driven forms, they rely on HTML directives for form control, making
them asynchronous and view-driven. Ideal for enterprise applications, they
efficiently handle complex, multi-step forms with intricate validation, reducing
the time and potential errors of manual form creation. This article delves into
using template-driven forms for practical scenarios like hospital or school
admissions, emphasizing the need for importing FormModule in Angular's
AppModule.
In Real life example, when you visit hospital a paper present to you and
requested to write basic info about your self. as well as in school admission form
also an example. These information uploaded to software. so form is basically a
paper that collect information. In technical prospective, angular provide us
template driven form to collect information about the things.
Form Setup
We make a basic form component with a basic form template and a simple
component, just like the user profile form component we started with in this
section:
Create a project
First, create a new project named angular-forms by using the following
command:
1. ng new angular-forms
Now, go to the project folder by using the following command.
1. cd angular-forms
Now, use the Angular CLI command ng generate class Hero to generate a new
class named Hero:
1. ng generate class Hero
Go to your project folder angular-forms and open the [Link] file under the app
module. Write the following code:
1. export class Hero {
2. constructor(
3. public id: number,
4. public name: string,
5. public power: string,
6. public alterEgo?: string
7. ) { }
8. }
The TypeScript compiler generates a public field for each public constructor
parameter and when you create new heroes, it automatically assign the
parameter's value to that field.
Here, alterEgo is optional and the constructor can omit it.
Create a Form component
An Angular form consists of two parts:
o HTML based template
o A component class to handle data and users
Now, generate a new component named HeroForm by using the following
command:
[Link] generate component HeroForm
Revise [Link] file
The [Link] file is used to define the application's root module. The
template-driven forms reside in their own module. You need to add the
FormsModule to the array of imports for the application module before using
forms.
1. import { NgModule } from '@angular/core';
2. import { BrowserModule } from '@angular/platform-browser';
3. import { FormsModule } from '@angular/forms';
4. import { AppComponent } from './[Link]';
5. import { HeroFormComponent } from './hero-form/hero-
[Link]';
6. @NgModule({
7. imports: [
8. BrowserModule,
9. FormsModule
10. ],
11. declarations: [
12. AppComponent,
13. HeroFormComponent
14. ],
15. providers: [],
16. bootstrap: [ AppComponent ]
17.})
[Link] class AppModule { }
Here, we have imported FormsModule and added the FormsModule to the list
of imports defined in the @NgModule decorator. This is used to access the
application to all of the template-driven forms features, including ngModel.
Revise [Link] file
The [Link] is used to host the new HeroFormComponent. It is the
application's root component. Write the following code in [Link]
1. <app-hero-form></app-hero-form>
Create an initial HTML form template
Use the following code in [Link]
1. <div class="container">
2. <h1>Hero Form</h1>
3. <form>
4. <div class="form-group">
5. <label for="name">Name</label>
6. <input type="text" class="form-control" id="name" required>
7. </div>
8. <div class="form-group">
9. <label for="alterEgo">Alter Ego</label>
10. <input type="text" class="form-control" id="alterEgo">
11. </div>
12. <button type="submit" class="btn btn-success">Submit</button>
13. </form>
14.</div>
Style the form
Open [Link] and use the following code to import the bootstrap file.
1. @import url('[Link]
[Link]');
Add power list by using *ngFor
The hero form can choose power lists from a fixed list of agency-approved
powers. Use the following HTML code immediately below the Alter Ego group
in [Link]
1. <div class="form-group">
2. <label for="power">Hero Power</label>
3. <select class="form-control" id="power" required>
4. <option *ngFor="let pow of powers" [value]="pow">{{pow}}</
option>
5. </select>
6. </div>
The basic template-driven form is completed now. You can use the ng serve
command to run the project.
OUTPUT:
Directives
The directives we need to construct template-driven forms in angular are in the
FormsModule, so import it and add it as an import to our NgModule.
One of the directives retrieved from the FormsModule is known as NgForm.
This directive's selector matches the <form> tag.
This ngForm object is hidden, but we can disclose it by attaching a local
template reference variable to the form element, as shown:
We can now use the variable userForm in our template to point to
our ngForm directive object.
Two-Way Data Binding
The form module in Angular implements a directive with
the [(ngModel)] selector, which allows us to quickly perform data binding in
two directions: from the view to the model and from the model to the view.
Terminology
[(...)] - Used for two-way binding Also known as banana-in-the-box as it looks
like the same.
Let's take a look at the following simple component:
Here, we've connected [(ngModel)] with the name, so whatever changes we will
do it will be stored in the name variable.
We already know that the (eventName) syntax is used to connect to events
generated by a certain component.
On the other side, we use the [propertyName]= "foo" syntax to create one-way
data binding by setting the value of the property.
The [(ngModel)] syntax combines both to provide bidirectional data binding.
Domain Model
In Angular, we normally won't data bind to a simple string or object on our
component but to a domain model specified via a class or interface, such as
User for our User Profile form.
Now, create an object for the interface User:
Now let's bind all our input controls to our userObj directly, like so:
Form Errors
In template-driven forms, we may handle two types of errors:
1. Handle form submission with ngSubmit and error handling in the submit
function.
2. Add a feature that disables the submit button at first and enables it only
after the form has been validated.
Sub-Form Components
The FormGroup is a FormControl collection. It may also include additional
FormGroups.
When we use the <form>, the ngForm directive constructs the top Level
FormGroup behind the scenes.
Using the ngModelGroup directive, we can create a new FormGroup. Let us add
the street, city, and Pincode form control to the address FormGroup.
Simply wrap the fields within a div element with the ngModelGroup directive
applied to it, as seen below:
Launch the app and submit it. The resulting item is seen below.
Validation
The validators in the model-driven method were defined via code in the
component.
In the template-driven technique, validators are defined in our template through
directives and HTML5 properties. Let's add validators to our form template.
Except for the language, all of the fields were necessary, so we'll just add the
required attribute to those input fields.
Validation Styling
To provide visuals on the screen, we employ several Form Control States such
as valid, touched, and dirty. These are the FormControl properties.
However, with template-driven forms in angular, no FormControl object is
created within the component. So, to access FormControl, we may use one of
the methods listed below.
1. Using .form property of ngForm
Using [Link], we can get the title FormControl
of userForm. We may retrieve the control status of the FormControl using this
object, as illustrated below.
2. Using local template reference variable.
To access control state properties of title control, we need to go
through [Link]. Using the ngModel directive, we can
make this shorter.
As shown below, we are creating a local reference to the title FormControl
using the ngModel directive
Now, we can access the control state of the title using just [Link], as
shown below.
Both ways will give the same output.
Validation Messages
In terms of form validation messages, we may utilize them the same way as in
model-driven forms. We may use the same HTML in our template-driven forms
as long as we name the local reference variables the same as the form controls
in the model-driven method, as seen below:
Submitting the Form
We may submit the form using the ngSubmit directive or on the Submit button's
click event. Either option is acceptable.
Let's add ngSubmit to the form:
[Link]
Now, we will create one method inside the component.
[Link]
Resetting the Form
As with the template-driven form, we may reset the form. As seen below,
Conclusion
Angular template-driven forms are the easiest way to create interactive
form
Will have to import FormsModule and add it to
the @NgModule imports array
Attaching the ngForm directive to the <form> tag will attach a form to
FormsModule, and now it'll have all the properties
Creating dynamic forms is possible
Handling errors, domain models and reset forms becomes easy when
using angular forms
Angular Model-Driven (Reactive) Forms:
Angular Model-Driven (Reactive) Forms are an effective tool for managing
form state & validation in Angular applications by synchronizing form controls
with model data. These forms take advantage of the capabilities of RxJS
observables to provide dynamic updates, strong validation, and seamless
integration with component functionality, hence improving the user experience
and developer efficiency.
Angular reactive forms follow a model-driven approach to handle form input
whose values can be changed over time. These are also known as model-driven
forms. In reactive forms, you can create and update a simple form control, use
multiple controls in a group, validate form values, and implement more
advanced forms.
Reactive forms use an explicit and immutable approach to manage the state of
the form at a given point of time. When we change the form state, it returns a
new state which manages the integrity of the models between changes. In
reactive forms, you build your own representation of a form in the component
class.
Reactive forms are easy to test because they assure consistent and predictable
data when requested.
How to add a single form control
In this section, we will describe how to add a single form control. Here, the
users have to enter their name into an input field, form captures that input value,
and displays the current value of the form control element.
Follow these steps:
1. Register the reactive forms module
You have to import ReactiveFormsModule from the @angular/forms package
and add it to your NgModule's imports array to use reactive forms.
1. import { ReactiveFormsModule } from '@angular/forms';
2. @NgModule({
3. imports: [
4. // other imports ...
5. ReactiveFormsModule
6. ],
7. })
8. export class AppModule { }
2. Generate and Import a new form control
First, generate a component for the control by using the following syntax:
1. ng generate component NameEditor
To register a single form control, you have to import the FormControl class into
your component and create a new instance of the form control to save as a class
property. The FormControl class is the basic building block used in reactive
forms.
Write the following code in [Link] file:
1. import { Component } from '@angular/core';
2. import { FormControl } from '@angular/forms';
3. @Component({
4. selector: 'app-name-editor',
5. templateUrl: './[Link]',
6. styleUrls: ['./[Link]']
7. })
8. export class NameEditorComponent {
9. name = new FormControl('');
10.}
3. Now, register the control in the template
After creating the control in the component class, you have to add it to the form
control element in the template. Use the formControl binding provided by
FormControlDirective to update the template with the form control.
1. <label>
2. Name:
3. <input type="text" [formControl]="name">
4. </label>
We have registered the form control to the name input element in the template.
Now, the form control and DOM element communicate with each other and the
view reflects changes in the model, and the model reflects changes in the view.
4. Display the component
Add the form control component to the template to display the form. Add the
following code to [Link].
1. <app-name-editor></app-name-editor>
CUSTOM VALIDATORS
Angular is a powerful front-end framework that allows developers to build
dynamic and interactive web applications. One of the key features of Angular is
its form handling capabilities. Angular provides a set of built-in validators to
perform common form validations such as required fields, email format, and
min/max length. However, there are cases where you need to implement custom
validation logic to meet your application’s specific requirements. In this article,
we will explore how to create custom validators in Angular with examples.
Why Custom Validators?
Custom validators in Angular are essential when you encounter validation
scenarios that cannot be achieved using the built-in validators. Some common
use cases for custom validators include:
1. Password Confirmation: You might want to ensure that two
password input fields match each other.
2. Unique Username: Checking if a chosen username is unique in your
application’s database.
3. Conditional Validation: Implementing complex validation rules
based on the state of other form controls.
Creating a Custom Validator
To create a custom validator in Angular, you need to define a function that
performs the validation logic and returns a validation error object if the
validation fails. This function should adhere to the signature
of ValidatorFn or AsyncValidatorFn based on whether your validation logic is
synchronous or asynchronous.
Synchronous Custom Validator
Here’s an example of a synchronous custom validator that checks if a name
contains only letters:
In this example, we define a letterValidatorfunction that returns a validator
function. The validator function takes a form control as an argument and checks
if it contains only letters. If not, it returns a validation error object with
a invalidSymbols property.
Usage:
Now if form control has invalid symbols we will see error message
And theinvalidSymbols property comes from LetterValidator
Usage of Custom Validator
Interaction with other form controls
Now, let’s assume our validator depends on the value of another form control. A
good example is the password confirmation input
So we need to create a custom validation to confirm that two password fields
match each other. First, let’s create the custom validator function for password
confirmation:
In this code, we define a passwordConfirmationValidator function that takes two
control names as arguments: controlName for the password field
and matchingControlName for the confirmation password field. This function
returns a validator function that compares the values of these two fields and sets
a passwordMismatch error if they do not match.
Now, let’s use this custom validator in an Angular component:
In this component, we import and use
the passwordConfirmationValidator function to create a custom validation rule
for the password confirmation. We apply this custom validator to the form group
by passing the control names ('password' and 'confirmPassword') to
the passwordConfirmationValidator function within the validator option.
Lastly, you can display an error message in your template when the passwords
don’t match:
In the template, we use the *ngIf directive to display an error message when the
'confirmPassword' field has the 'passwordMismatch' error set, indicating that the
passwords do not match.
With this custom validation in place, your Angular registration form will ensure
that the user enters the same password in both the ‘password’ and
‘confirmPassword’ fields
Asynchronous Custom Validator
In this example we will check checking if a chosen username is unique in our
application’s database.
For asynchronous validation, you can use the AsyncValidatorFn. Here's an
example of an asynchronous custom validator that checks if a username is
already taken:
In this example, we define an uniqueUsernameValidator function that returns an
asynchronous validator function. This validator function checks if the username
already exists by calling a userService method. It returns an observable that
emits a validation error object if the username is taken or null if it's available.
Html
<mat-form-field>
<mat-label>User name</mat-label>
<input matInput type="text" placeholder="Name" formControlName="name" />
<mat-error *ngIf="[Link]['name'].hasError('usernameTaken')">
Username is taken
</mat-error>
</mat-form-field>
Example
Async validator example
Note: When the request is pending, [Link] becomes false
Conclusion
Custom validators are a powerful tool in Angular for handling complex form
validation requirements. By creating custom validators, you can tailor your
validation logic to the specific needs of your application. Whether you need to
perform synchronous or asynchronous validation, Angular provides a flexible
framework to implement and use custom validators effectively. So, don’t
hesitate to leverage custom validators to enhance the user experience in your
Angular applications.
Dependency Injection in Spring
AngularJS comes with a built-in dependency injection mechanism. It facilitates
you to divide your application into multiple different types of components
which can be injected into each other as dependencies.
Dependency Injection is a software design pattern that specifies how
components get holds of their dependencies. In this pattern, components are
given their dependencies instead of coding them within the component.
Modularizing your application makes it easier to reuse, configure and test the
components in your application. Following are the core types of objects and
components:
o value
o factory
o service
o provider
o constant
These objects and components can be injected into each other using AngularJS
Dependency Injection.
Value
In AngularJS, value is a simple object. It can be a number, string or JavaScript
object. It is used to pass values in factories, services or controllers during run
and config phase.
1. //define a module
2. var myModule = [Link]("myModule", []);
3. //create a value object and pass it a data.
4. [Link]("numberValue", 100);
5. [Link]("stringValue", "abc");
6. [Link]("objectValue", { val1 : 123, val2 : "abc"} );
Here, values are defined using the value() function on the module. The first
parameter specifies the name of the value, and the second parameter is the value
itself. Factories, services and controllers can now reference these values by their
name.
Injecting a value
To inject a value into AngularJS controller function, add a parameter with the
same when the value is defined.
1. var myModule = [Link]("myModule", []);
2. [Link]("numberValue", 100);
3. [Link]("MyController", function($scope, numberValue) {
4. [Link](numberValue);
5. });
Factory
Factory is a function that is used to return value. When a service or controller
needs a value injected from the factory, it creates the value on demand. It
normally uses a factory function to calculate and return the value.
Let's take an example that defines a factory on a module, and a controller which
gets the factory created value injected:
1. var myModule = [Link]("myModule", []);
2. [Link]("myFactory", function() {
3. return "a value";
4. });
5. [Link]("MyController", function($scope, myFactory) {
6. [Link](myFactory);
7. });
Injecting values into factory
To inject a value into AngularJS controller function, add a parameter with the
same when the value is defined.
1. var myModule = [Link]("myModule", []);
2. [Link]("numberValue", 100);
3. [Link]("MyController", function($scope, numberValue) {
4. [Link](numberValue);
5. });
Note: It is not the factory function that is injected, but the value produced by
the factory function.
Service
In AngularJS, service is a JavaScript object which contains a set of functions to
perform certain tasks. Services are created by using service() function on a
module and then injected into controllers.
1. //define a module
2. var mainApp = [Link]("mainApp", []);
3. ...
4. //create a service which defines a method square to return square of a nu
mber.
5. [Link]('CalcService', function(MathService){
6. [Link] = function(a) {
7. return [Link](a,a);
8. }
9. });
10.//inject the service "CalcService" into the controller
[Link]('CalcController', function($scope, CalcService, defau
ltInput) {
12. $[Link] = defaultInput;
13. $[Link] = [Link]($[Link]);
14. $[Link] = function() {
15. $[Link] = [Link]($[Link]);
16. }
17.});
Provider
In AngularJS, provider is used internally to create services, factory etc. during
config phase (phase during which AngularJS bootstraps itself). It is the most
flexible form of factory you can create. Provider is a special factory method
with a get() function which is used to return the value/service/factory.
1. //define a module
2. var mainApp = [Link]("mainApp", []);
3. ...
4. //create a service using provider which defines a method square to return
square of a number.
5. [Link](function($provide) {
6. $[Link]('MathService', function() {
7. this.$get = function() {
8. var factory = {};
9. [Link] = function(a, b) {
10. return a * b;
11. }
12. return factory;
13. };
14. });
15.});
Constants
You cannot inject values into the [Link]() function. Instead constants
are used to pass values at config phase.
1. [Link]("configParam", "constant value");
Let's take an example to deploy all above mentioned directives.
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <title>AngularJS Dependency Injection</title>
5. </head>
6. <body>
7. <h2>AngularJS Sample Application</h2>
8.
9. <div ng-app = "mainApp" ng-controller = "CalcController">
10. <p>Enter a number: <input type = "number" ng-model = "number"
/></p>
11. <button ng-click = "square()">X<sup>2</sup></button>
12. <p>Result: {{result}}</p>
13. </div>
14.
15. <script src = "[Link]
[Link]"></script>
16.
17. <script>
18. var mainApp = [Link]("mainApp", []);
19.
20. [Link](function($provide) {
21. $[Link]('MathService', function() {
22. this.$get = function() {
23. var factory = {};
24.
25. [Link] = function(a, b) {
26. return a * b;
27. }
28. return factory;
29. };
30. });
31. });
32.
33. [Link]("defaultInput", 10);
34.
35. [Link]('MathService', function() {
36. var factory = {};
37.
38. [Link] = function(a, b) {
39. return a * b;
40. }
41. return factory;
42. });
43.
44. [Link]('CalcService', function(MathService){
45. [Link] = function(a) {
46. return [Link](a,a);
47. }
48. });
49.
50. [Link]('CalcController', function($scope, CalcService,
defaultInput) {
51. $[Link] = defaultInput;
52. $[Link] = [Link]($[Link]);
53.
54. $[Link] = function() {
55. $[Link] = [Link]($[Link]);
56. }
57. });
58. </script>
59. </body>
60.</html>
Dependency injection (DI) is a programming method that separates component
creation and usage. The design pattern appears in object-oriented
programming and adheres to the SOLID principles (specifically the S and
the D). Similar ideas also apply to other programming paradigms, such
as procedural or functional programming.
The term consists of two keywords, which help demystify the concept:
Dependencies. Code components rely on many objects and services
(dependencies) to carry out their tasks. Different dependencies exist, such
as outside resources, other objects, or services.
Injection. Components do not make or link dependencies internally in
DI. Instead, the technique provides (injects) dependencies from the
outside. This approach creates a separation between components and
dependencies.
Dependencies come in various shapes and forms. They are essential for a
component to work but are not part of the component itself. APIs,
libraries, databases, and other components can all act as dependencies.
Dependency injection solves the dependency management challenge. By
separating dependency management from a component, an external source
creates and manages the dependencies.
Separation (or decoupling) reduces the number of connections between
components and modules. Fewer connections result in simplified maintenance
and flexibility. As a result, code becomes reusable because components are
independent and applicable to various contexts. Teams do not require constant
coordination and can develop modules in parallel.
Why Use Dependency Injection?
There are several key reasons to use dependency injection. Some of the main
benefits include:
Readability. DI promotes division between a component's logic and its
dependencies. Code is easier to read and better organized.
Reusability. Components with injected dependencies are easy to reuse
for different projects due to being independent. DI provides a templating
approach to coding, reducing repeated code blocks and rewriting across
different projects.
Testability. Dependency injection simplifies writing unit tests for
individual components. Regular testing leads to dependable code with
fewer bugs.
Maintainability. Due to fewer connections between components and
modules, changing or improving individual code parts does not affect
other parts of the code.
Dependency Injection Types
Developers use various techniques to implement dependency injection. Choose
the approach that best suits the requirements, programming language, and use
case. Below is a brief overview and example of some dependency injection
types.
Constructor Injection
Constructor injection is a dependency injection type that injects dependencies
through a constructor. When an instance of a class or object is created, the
constructor provides the dependencies during creation. As a result, the class or
object runs correctly and immediately has all the necessary dependencies.
Use constructor injection when the dependencies are required for a class or
object to function. The dependencies are injected during class or object
instantiation and make dependencies immediately available to a class or object
instance.
Setter Injection
Setter injection is a dependency injection that provides dependencies through
setter methods or class properties. A developer updates the dependencies
manually after object or class instantiation. As a result, the object receives
appropriate dependencies when the setter methods are called.
Use setter injection when a class or object functions without mandatory
dependencies. In this case, the dependencies are optional during instantiation
and can be injected after runtime. This approach allows modifying
dependencies dynamically after object creation.
Method Injection
Method injection (or parameter injection) is a dependency injection type that
provides dependencies as method parameters. The class or object expects
dependencies as arguments when calling a method.
Use method injection for fine-grained dependency injection based on individual
methods. Method injection achieves the highest decoupling degree and is useful
when a class has multiple methods that do not require the same dependencies.
How Does Dependency Injection Work?
The dependency injection process uses four main components (roles):
1. Service. A component that provides a function or service. Other components
depend on the provided service.
2. Client. A component or class that depends on the service to perform tasks.
The client does not create or manage the service; it relies on a DI process to
provide the service.
3. Injector. Creates and manages service instances and injects them into clients.
The injector resolves all dependencies and connects components as required.
4. Interface. The interface (or contract) defines methods or properties a service
implements. The abstraction is an agreement between the service and the client,
ensuring the service addresses all rules and expectations.
The dependency injection process goes through the following steps:
Defining dependencies. Determine resources that classes and
components need to function.
Defining interfaces (contracts). Create an interface for each
dependency. Provide the methods or properties that serve as contract
rules.
Injecting dependencies. Choose a mechanism to inject dependencies
into classes or components. Depending on the mechanism, this step
happens manually, with a DI container or a framework.
Using dependencies. Classes and components use the dependencies by
interacting with the defined contracts.
Dependency Injection Advantages and Disadvantages
There are both advantages and disadvantages when implementing dependency
injection. Although the approach improves code maintainability, there's a steep
learning curve and added code complexity.
Below is a brief overview of DI's main advantages and disadvantages.
Advantages
The main advantages of dependency injection are:
Logical separation. Loose coupling between components and
dependencies makes code easier to read and maintain. Classes and objects
do not handle dependency instantiation or management.
Improved testing. DI simplifies unit testing. Creating mock
dependencies or testing individual components is simplified.
Flexible dependency management. Separating dependencies and
components provides flexibility. Different dependencies can be injected,
which creates an easily adaptable environment.
Reusable components. Due to loose coupling between components and
dependencies, the code is reusable in different contexts and
environments.
Simpler maintenance. Upgrading libraries or components does not affect
the underlying dependent class.
Concurrent development. Developers can work on modules and
dependencies in parallel while adhering to the defined contracts.
Disadvantages
The disadvantages of dependency injection are:
Complexity. When handling many dependencies or complex
configurations, DI additionally increases code complexity.
Learning curve. The concepts behind DI and when to apply them take
time to grasp fully. Initial project development slows down due to the
learning curve.
Overhead. DI is not suitable for smaller projects, as it adds redundant
overhead.
Runtime errors. Dependencies that are not carefully injected result in
runtime errors. Troubleshooting is challenging, especially in complex
environments.