Directive In Angular
In this article, we will understand what directive is in Angular and why we need directive, and how to create custom directives.
So firstly I will try to explain what directive is in Angular:
Angular Directive is a TypeScript class which is declared as a @directive decorator.
The directives allow you to attach behavior to DOM elements and the @directive decorator provides you with an additional metadata that determines how directives should be processed, instantiated, and used at run-time.
Angular Directive is basically a class with a @Directive decorator. You might be wondering, what are decorators? Decorators are functions that modify JavaScript classes. Decorators are used for attaching metadata to classes, it knows the configuration of those classes and how they should work.
Three Types of Directives Available in Angular
Component Directives
These form the main class with details of how the component should be processed, instantiated and used at runtime.
Attribute Directives
Attribute directives deal with changing the look and behavior of the dom element.
Structural Directives
A structure directive basically deals with manipulating the dom elements. Structural directives have a * sign before the directive. For example, *ngIf and *ngFor.
Why We Need Directives in Angular
If you want similar functionality across all components, for example, fade in – fade out or you need some input type which provide auto-suggestive Google places (I'll explain later in detail), you can take two approaches. You can write code in all components or, in programming language you can create a function and that function will provide the same functionality across all components where you will use this function.
Similarly, in Directive, you can write a directive and add behavior inside it. Then whenever you need that behaviour, you can import the directive.
Custom Directive
For creating Custom Directive in Angular, I have to take an example of auto-suggestive Google places by input control.
Before we begin…
To use Google places autocomplete API, we need an API key. To obtain an API key, please go to the
Google maps platform and create a new project.
After that, install the package with the following command,
npm i --save-dev @types/googlemaps
In your index page copy that script in your head section with your secret key:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR SECRET KEY&libraries=places" async defer></script>
Create a directory in your app root folder with the following command,
ng g d google-places.directive
Now edit your google-places.directive.ts.
-
- import {
- Directive,
- ElementRef,
- OnInit,
- Output,
- EventEmitter
- } from '@angular/core';
- @Directive({
-
- selector: '[google-place]'
- })
- exportclassGooglePlacesDirectiveimplementsOnInit {
-
- @Output() onSelect: EventEmitter < any > = newEventEmitter();
- privateelement: HTMLInputElement;
- constructor(privateelRef: ElementRef) {
-
-
- this.element = elRef.nativeElement;
- }
- ngOnInit() {
- constautocomplete = newgoogle.maps.places.Autocomplete(this.element);
-
- google.maps.event.addListener(autocomplete, 'place_changed', () => {
-
- this.onSelect.emit(this.getFormattedAddress(autocomplete.getPlace()));
- });
- }
-
-
- getFormattedAddress(place) {
-
-
- constlocation_obj = {};
-
- for (const_valueinplace.address_components) {
- constitem = place.address_components[_value];
- location_obj['formatted_address'] = place.formatted_address;
- if (item['types'].indexOf('locality') > -1) {
- location_obj['locality'] = item['long_name'];
- }
- elseif(item['types'].indexOf('administrative_area_level_1') > -1) {
- location_obj['admin_area_l1'] = item['short_name'];
- }
- elseif(item['types'].indexOf('street_number') > -1) {
- location_obj['street_number'] = item['short_name'];
- }
- elseif(item['types'].indexOf('route') > -1) {
- location_obj['route'] = item['long_name'];
- }
- elseif(item['types'].indexOf('country') > -1) {
- location_obj['country'] = item['long_name'];
- }
- elseif(item['types'].indexOf('postal_code') > -1) {
- location_obj['postal_code'] = item['short_name'];
- }
- }
- returnlocation_obj;
- }
- }
Code Explanation
We have done things right here.
We created a characteristic getFormattedAddress which takes a Google place object as an argument and parses it to create a useful deal with an item.
We introduced an event listener to the autocomplete API, so as to fire each time the places are changed, and we use this event listener to emit our own event to be able to parse the place object.
We have uncovered this event via an onSelect event emitter.
In your app.component.html:
- <divstyle="text-align:center">
- <h1> Welcome to {{ title }}! </h1>
- </div>
- <divclass="input-container">
- <input type="text" class="google-place-input" google-place (onSelect)="setAddress($event)" placeholder="Type to search..">
- <!-- Displaying the contents of the address object received from our event emitter -->
- <ulstyle="list-style-type: none;">
- <li*ngFor="let key of addrKeys">
- <spanstyle="font-weight: bold">{{key}}</span>: <span>{{addr[key]}}</span>
- </li>
- </ul>
- </div>
In your app.component.ts,
- import {
- Component,
- NgZone
- } from '@angular/core';
- @Component({
- selector: 'app-google-place-search',
- templateUrl: './google-place-search.component.html',
- styleUrls: ['./google-place-search.component.css']
- })
- exportclassAppComponent {
- publictitle = 'Places';
- publicaddrKeys: string[];
- publicaddr: object;
-
-
- setAddress(addrObj) {
-
-
- this.zone.run(() => {
- this.addr = addrObj;
- this.addrKeys = Object.keys(addrObj);
- });
- }
- constructor(privatezone: NgZone) {}
- }
Add in .css file of your appcomponent,
- .input - container {
- text - align: center;
- width: 100 % ;
- }.google - place - input {
- width: 50 % ;
- min - width: 300 px;
- height: 1.5 rem;
- font - size: 1.5 rem;
- padding: 0.5 rem;
- }
Now run ng serve, and you will get the output,