Tuesday, October 25, 2022
Angular tutorial Part 3 - Learn Angular Services and Dependency injection Forms
Angular
Services and
Dependency injection
Dependency
Injection
• Dependencies are
services or objects that a class needs to perform its function.
• Dependency injection,
or DI, is a design pattern in which a class requests dependencies from external
sources rather than creating them.
• Angular's DI
framework provides dependencies to a class upon instantiation. Use Angular DI
to increase flexibility and modularity in your applications.
• We shall see dependency injection using services
Services
• A service is a
class with a focusedpurpose. We often create a service to implement
functionality that is independent from any particular component.
• Services are used
to share the data and logic across components or to encapsulate external
interactions such as data access.
• To create a service
class there is no need to do anything angulars pecific,noMetadata,naming
convention requirement or some functional interface that needs to be
implemented.They'rejust plain old classes that you create to modularize
reusable code.
• Services are not
only beneficial for modularity and single responsibility,but it also makes the
code more testable.
• Dataservice is a
class that will handle getting and setting data from your data store
Creating
injectable service
• Create an injectable service using the command
• Ng generate service myservice in the angular app
folder
• It will create the service shell code
• import { Injectable
} from '@angular/core';
• @Injectable({ providedIn: 'root', })
• export class
myService { constructor() { } }
• The @Injectable()
decorator specifies that Angular can use this class in the DI system. Root
gives application wide access to service.
•
We will add
business logic to get todays date to the service.
• showTodayDate() {
• let ndate = new Date();
• return ndate;
• }
• To add this service to component inject a dependency in a component's
constructor(), supply a
• constructor argument with the dependency type.
• 1. import { MyserviceService } from './myservice.service';
• 2. constructor(private myservice: MyserviceService ){}
•
Service
•
You can also inject
service in the main module
•
So in the
app-module.ts we can inject the service
• import { MyserviceService } from './myservice.service';
•
providers: [MyserviceService],
•
Component provider
and Module provider are different, If its injected in the module provider,it’s
available to the whole app,it can also be specifically be injected into a
component.
•
@Component({
/* . . . */ providers: [UserService] })
Forms
– two ways to create forms in angular
• Reactive
forms provide direct, explicit access to the underlying forms object
model. Compared to template-driven forms, they are more robust: they're more
scalable, reusable, and testable. If forms are a key part of your application,
or you're already using reactive patterns for building your application, use
reactive forms.
• Template-driven
forms rely on directives in the template to create and manipulate the
underlying object model. They are useful for adding a simple form to an app,
such as an email list signup form. They're straightforward to add to an app,
but they don't scale as well as reactive forms. If you have very basic form
requirements and logic that can be managed solely in the template,
template-driven forms could be a good fit.
Core
classes
• Both reactive and
template-driven forms track value changes between the form input elements that
users interact with and the form data in
your component model.
• Both reactive and
template-driven forms are built on the following base classes.
• FormControl tracks
the value and validation status of an individual form control.
• FormGroup tracks
the same values and status for a collection of form controls.
• FormArray tracks
the same values and status for an array of form controls.
• ControlValueAccessor
creates a bridge between Angular FormControl instances and built-in DOM
elements.
Building
a reactive form
• With reactive
forms, you define the form model directly in the component class. The
[formControl] directive links the explicitly created FormControl instance to a
specific form element in the view, using
an internal value accessor.
• import { Component
} from '@angular/core';
• import { FormControl
} from '@angular/forms';
• @Component({
selector: 'app-reactive-favorite-color', template: ` Favorite Color: <input
type="text" [formControl]="favoriteColorControl"> ` })
• export class
FavoriteColorComponent { favoriteColorControl = new FormControl(''); }
//creates new form control instance
Direct access to forms model in a
reactive form
Template
uses ngmodel for binding and not form control instance
Building
template form
• In template-driven
forms, the form model is implicit, rather than explicit. The directive NgModel
creates and manages a FormControl
instance for a given form element.
• import { Component
} from '@angular/core';
• @Component({
selector: 'app-template-favorite-color', template: ` Favorite Color: <input
type="text" [(ngModel)]="favoriteColor"> ` })
export class FavoriteColorComponent {
• favoriteColor = ''; }
• In a
template-driven form the source of truth is the template. You do not have
direct programmatic access to the FormControl
Data
flowin reactive forms
• The user types a
value into the input element, in this case the favorite color Blue.
• The form input
element emits an "input" event with the latest value.
• The control value
accessor listening for events on the form input element immediately relays the
new value to the FormControl instance.
• The FormControl
instance emits the new value through the valueChanges observable.
• Any subscribers to
the valueChanges observable receive the new value.
Data
flow in reactive forms
• The user calls the
favoriteColorControl.setValue() method, which updates the FormControl value.
• The FormControl
instance emits the new value through the valueChanges observable.
• Any subscribers to
the valueChanges observable receive the new value.
• The control value
accessor on the form input element updates the element with the new value.
Data
flow in template forms
• The user types Blue
into the input element.
• The input element
emits an "input" event with the value Blue.
• The control value
accessor attached to the input triggers the setValue() method on the FormControl
instance.
• The FormControl
instance emits the new value through the valueChanges observable.
• Any subscribers to
the valueChanges observable receive the new value.
• The control value
accessor also calls the NgModel.viewToModelUpdate() method which emits an
ngModelChange event.
• Because the
component template uses two-way data binding for the favoriteColor property,
the favoriteColor property in the component is updated to the value emitted by
the ngModelChange event (Blue).
Data
flow in template forms
• The model-to-view
diagram shows how data flows from model to view when the favoriteColor changes
from Blue to Red, through the following steps
• The favoriteColor
value is updated in the component.
• Change detection
begins.
• During change
detection, the ngOnChanges lifecycle hook is called on the NgModel directive
instance because the value of one of its inputs has changed.
• The ngOnChanges()
method queues an async task to set the value for the internal FormControl
instance.
• Change detection
completes.
• On the next tick,
the task to set the FormControl instance value is executed.
• The FormControl
instance emits the latest value through the valueChanges observable.
• Any subscribers to
the valueChanges observable receive the new value.
• The control value
accessor updates the form input element in the view with the latest
favoriteColor value.
Form
Validations
• Reactive
forms define custom validators as functions that receive a
control to validate.
• Template-driven
forms are tied to template directives, and must provide custom
validator directives that wrap validation functions.
Reactive
forms with form controls
• There are three
steps to using form controls.
• Register the
reactive forms module in your application. This module declares the
reactive-form directives that you need to use reactive forms.
• Generate a new
FormControl instance and save it in the component.
• Register the
FormControl in the template.
• import { ReactiveFormsModule
} from '@angular/forms'; @NgModule({
• imports: [ // other imports ... ReactiveFormsModule
], })
Adding
form control to component
• import { FormControl
} from '@angular/forms';
• name = new FormControl('');//create
a new instance of form control
• After you create
the control in the component class, you must associate it with a form control
element in the template.
• Bind the variable using form control
• <label
for="name">Name: </label> <input id="name"
type="text" [formControl]="name">
• Display the value
• <p>Value: {{
name.value }}</p>
• updateName() {
this.name.setValue('Nancy'); }
• Updates the value from a component method
• <button
(click)="updateName()">Update Name</button>
• Method binding to update the variable
Form
Group controls
• Forms typically
contain several related controls. Reactive forms provide two ways of grouping
multiple related controls into a single input form.
• A form group defines
a form with a fixed set of controls that you can manage together. Form group
basics are discussed in this section. You can also nest form groups to
create more complex forms.
• A form array defines
a dynamic form, where you can add and remove controls at run time. You can also
nest form arrays to create more complex forms. For more about this option,
see Creating dynamic forms.
Building
a form group control
• import { FormGroup,
FormControl } from '@angular/forms‘;
• To add a form group
to this component, take the following steps.
• Create a FormGroup
instance.
• Associate the
FormGroup model and view.
• Save the form data.
Creating
a form group
• import { Component
} from '@angular/core';
• import { FormGroup,
FormControl } from '@angular/forms';//import the formgroup
• @Component({
• selector: 'app-profile-editor',
• templateUrl:
'./profile-editor.component.html',
• styleUrls: ['./profile-editor.component.css']
• })
• export class ProfileEditorComponent
{
• profileForm = new FormGroup({ //instantiate new form group
• firstName: new FormControl(''), //within
from group instantiate new form control
• lastName: new FormControl(''),
• });
• }
Associate the FormGroup model and
view
• Build the form ,associate the formgroup and submit the
data.
• <form
[formGroup]="profileForm" (ngSubmit)="onSubmit()">
• <label for="first-name">First
Name: </label>
• <input id="first-name"
type="text" formControlName="firstName">
• <label for="last-name">Last
Name: </label>
• <input id="last-name"
type="text" formControlName="lastName">
• </form>
• In Submit method access the form group values
• onSubmit()
• { // TODO: Use EventEmitter
with form value
• console.warn(this.profileForm.value);
• }
There are two ways to update the
model value:
• Use the setValue()
method to set a new value for an individual
• control. The
setValue() method strictly adheres to the structure of the form group and
replaces the entire value for the control.
• Use the
patchValue() method to replace any properties defined in the object that have
changed in the form model.
• updateProfile() {
• this.profileForm.patchValue({ firstName: 'Nancy', address: { street: '123 Drew Street' }
• });
• }
Validations
• <p>Complete
the form to enable button.</p>
• <button
type="submit"
[disabled]="!profileForm.valid">Submit</button>
• The above mark up allows submission only if form
control values are valid. These validation rules will be defined by you using
validators.
Validation
in template forms
• <input
type="text" id="name" name="name"
class="form-control"
• required minlength="4"
appForbiddenName="bob"
[(ngModel)]="hero.name" #name="ngModel">
• <div
*ngIf="name.invalid && (name.dirty || name.touched)" class="alert"> <div
*ngIf="name.errors?.required">
Name is required.
• </div>
<div *ngIf="name.errors?.minlength">
• Name must be at least 4 characters
long. </div> <div
*ngIf="name.errors?.forbiddenName">
• Name cannot be Bob.
• </div>
• </div>
Validation
in template forms
• The <input>
element carries the HTML validation attributes: required and minlength. It also
carries a custom validator directive, forbiddenName. For more information, see
the Custom validators section.
• #name="ngModel"
exports NgModel into a local variable called name. NgModel mirrors many of the
properties of its underlying FormControl instance, so you can use this in the
template to check for control states such as valid and dirty. For a full list
of control properties, see the AbstractControl API reference.
• The *ngIf on the
<div> element reveals a set of nested message divs but only if the name
is invalid and the control is either dirty or touched.
• Each nested
<div> can present a custom message for one of the possible validation
errors. There are messages for required, minlength, and forbiddenName.
Validation
in Reactive forms
• Built in validators can be used at the form control
level to validate inputs
• Custom validators can also be used to validate. Lets
look at an example
• name: new
FormControl(this.hero.name, [ Validators.required, Validators.minLength(4), //these 2 validators
check for required and length of input.
• forbiddenNameValidator(/bob/i) // <--
Here's how you pass in the custom validator. ]),
Building
a custom validator
• forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
• //first line creates a function which accepts a regularexp.//It also implements interface validatorfn .A function that receives a control and synchronously returns a map of validation errors if present, otherwise null.
• //the interfae implemented method.is passed the control.valuereturn (control: AbstractControl): ValidationErrors | null => {
• return (control: AbstractControl): ValidationErrors | null => {
• const forbidden = nameRe.test(control.value)//this will return true or false nbased on whether the control,value, matches with the regular expression // added in the validatr
• return forbidden ? {forbiddenName: {value: control.value}} : null;
• };
• }//imports of
validator,validationerrors,validationfn required from angular/forms
• Ternary operator
• function
getFee(isMember) { return (isMember ?
'$2.00' : '$10.00');}
• If true 2 ,if null
or false 10
Creating
a user registration form demo
• ng g component
formapp to generate form app
Angular tutoral part 2 - AngularDirectives, Built In and Custom
Angular part
2
Directives
Built In
Custom
Directives
• Directives are
classes that add additional behavior to elements in your Angular applications.
Use Angular's built-in directives to manage forms, lists, styles, and what
users see.
• Example
@component itself is a directive
• Two types
• Built in
Directives
• Custom
Directives
Builtin directives
• Also
called built-in structural directives
• NgClass—adds and
removes a set of CSS classes.
• NgStyle—adds and
removes a set of HTML styles.
• NgModel—adds
two-way data binding to an HTML form element.
• NgIf—conditionally
creates or disposes of subviews from the template.
• NgFor—repeat a
node for each item in a list.
• NgSwitch—a set of
directives that switch among alternative views.
NGIF
• Helps to
conditionally render elements
• Add or
remove an element by
• applying an
NgIf directive to a host element.
• <app-item-detail
*ngIf="isActive" [item]="item"></app-item-detail>
• Check nulls
• <div
*ngIf="currentCustomer">Hello,
{{currentCustomer.name}}</div>
NGFOR
• Use to Loop
through array elements ,render a list from an array property
• Define a block of
HTML that determines how Angular renders a single item.
• To list your
items, assign the short hand let item of items to *ngFor.
• <div
*ngFor="let item of items">{{item.name}}</div>
• Store each item
in the items array in the local item looping variable
• Make each item
available to the templated HTML for each iteration
• Translate
"let item of items" into an <ng-template> around the host
element
• Repeat the
<ng-template> for each item in the list
NGFOR2
• Get the index of
*ngFor in a template input variable and
• use it in the
template.
• <div
*ngFor="let item of items; let i=index">
• {{i + 1}} -
{{item.name}}</div>
• Reduce the number
of calls your application makes to the server by tracking changes to an item
list. With the *ngFor trackBy property, Angular can change and re-render only
those items that have changed, rather than reloading the entire list of items.
• method
• In this example,
the value to track is the item's id. If the browser has already rendered id,
Angular keeps track of it and doesn't re-query the server for the same id.
• trackByItems(index:
number, item: Item): number { return item.id; }
• <div
*ngFor="let item of items; trackBy: trackByItems">
• ({{item.id}})
{{item.name}}
• </div>
Ngclass
• Add or remove
multiple CSS classes simultaneously with ngClass.
• <div
[ngClass]="currentClasses">This div is initially saveable,
unchanged, and special.</div>
• Here ngclass is
calling a method which sets the classes
• Method
• currentClasses:
Record<string, boolean> = {};
• setCurrentClasses()
{ // CSS classes: added/removed per current state of component properties
• this.currentClasses
= { saveable: this.canSave, modified: !this.isUnchanged, special:
this.isSpecial };
NGstyle
• Use
NgStyle to set multiple inline styles simultaneously, based on the state of the
component.
• To
use NgStyle, add a method to the component class.
• In
the following example, setCurrentStyles() sets the property currentStyles with
an object that defines three styles, based on the state of three other
component properties.
• Method
• currentStyles:
Record<string, string> = {};
• setCurrentStyles()
{
• //
CSS styles: set per current state of component properties
• this.currentStyles
= {
• 'font-style': this.canSave ?
'italic' : 'normal',
• 'font-weight':
!this.isUnchanged ? 'bold' : 'normal',
• 'font-size': this.isSpecial ?
'24px' : '12px' };}
• Using
Ngstyle <div [ngStyle]="currentStyles"> This div is
initially italic, normal weight, and extra large (24px). </div>
Ngmodel => 2way property binding
• Use the NgModel
directive to display a data property and update that property when the user
makes changes.
• Define the
property
• @Input() property1
='test';
• add the ngmodel
directive
• This will add two
way binding
• <input
[(ngModel)]="property1" id="example-ngModel">
Ngswitch
• The
ngSwitch is an Angular directive, which allows us to display one or more DOM
elements based on some pre-defined condition.
• The
following is the syntax of ngSwitch. It contains three separate directives.
ngSwitch, ngSwitchCase & ngSwitchDefault.
• An
example switch ,this will basically be using num as property to store,and based
on the correct value that you in put in input field,will be passed to the
switch and finally the switchcase ,the corresponding “one” or “two”value will
be shown in ui
• Input string :
<input type='text' [(ngModel)]="num" />
•
• <div
[ngSwitch]="num">
• <div
*ngSwitchCase="'1'">One</div>
• <div
*ngSwitchCase="'2'">Two</div>
Custom Directive
• Custom
directive can be created by annotating a class a @Directive
• Look at the
appexample directive
• Usage in
html<button appExample defaultColor="red">Button</button>
• Import { HostListener, Directive, ElementRef, Renderer2, Input, OnInit } from '@angular/core'
•
@Directive({
• selector: '[appExample]',
• })
• export class ExampleDirective implements OnInit {
• @Input() defaultColor: string//
This makes the defaultColor variable changeable 2way binding
•
Adding events to custom directive
• Using
@HostListener annotation,more interactive logic can be added to the
directive. Decorator that declares a DOM event to listen for, and
provides a handler method to run when that event occurs.
• @HostListener('mouseenter') onMouseEnter() {
• this.setBgColor('yellow')
• }
•
@HostListener('mouseleave') onMouseLeave() {
• this.setBgColor('white')
• }
• This annotation
when added to the custom directive class ,will start listening to mouseevents
and fire the corresponding method
Custom directive
• Initially the
custom directive will make the button appear red,
• On mousenter it
will become yellow ,then when mouse is moved out
• The button
background color will become white
Custom Directive command
ng generate directive example app