Friday, 23 March 2018

Dynamic model with add and delete operations - Angular

Angular 2(+)Dynamic modelAdd

In this article I am going to discuss about setting a dynamic model for ngFor (looped) items. Our html contains a text box and a select box, user can add more similar blocks by clicking on add button. Each blocks are associated with a delete button so that user can delete as well. After filling all fields user can click on save button where we will be getting the complete list of the changes. Check below image.

As we need to loop the items to show in the UI, set dynamic model for values. So that we can collect all the details added by user. It is very simple, check the component code first.

Component


import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

  userDetails: any = [];

  constructor() { }

  ngOnInit() {
    this.additemToUserDetails();
  }
  additemToUserDetails() {
    let _userItem = {
      name: '',
      gender: '',
      id: new Date().getTime()
    }
    this.userDetails.push(_userItem);
  }
  deleteItem(user) {
    for (var i = 0; i < this.userDetails.length; i++) {
      if (user.id == this.userDetails[i].id) {
        this.userDetails.splice(i, 1);
      }
    }
  }
  saveModel() {
    console.log(this.userDetails);
  }
}

Here we have created a simple object and pushing to userDetails while clicking on add button. I am calling the method under ngOnInit as well to keep one item default in the list. However you can modify the code according to your needs. Check below html code more info.

Html


<div class="dynamicModel">

  <div *ngFor="let user of userDetails">

    <input [(ngModel)]="user.name" type="text" value="" placeholder="name"> Gender:

    <select [(ngModel)]="user.gender">
      <option value="True">Male</option>
      <option value="False">Female</option>
    </select>

    <button class="btn btn-primary btn-sm" *ngIf="userDetails.length>1" (click)="deleteItem(user)">Delete</button>

  </div>

  <button class="btn btn-primary btn-sm" (click)="additemToUserDetails()">Add +</button>

</div>

<div>
  <button class="btn btn-primary" (click)="saveModel()">Save</button>
</div>

You can update the look and feel using css. Clicking on delete button we are splicing the selected item from our main object and the same will be updated in the html as well. I have used current time as id for this demo. This line *ngIf="userDetails.length > 1" is for hiding delete button if only one item is available. On click of saveModel we can collect all the user entered values. You can build your validation logic on top of this, for example disabling submit button until all the mandatory fields are filled etc.

I have added a console.log() for the output. Click on save button and see your browser console for the result.

You can fetch select box values also from the component instead of hardcoding in the html. For example check below code.

Component


 genderList: any = [
    { name: 'Male', value: 'male' },
    { name: 'Female', value: 'female' }
  ]

Html


<select [(ngModel)]="user.gender">
   <option *ngFor="let g of genderList" [value]="g.value">{{g.name}}</option>
</select>

There is no other changes required. Click on save you can see the user entered values in the console. Similarly you can add more things and no need to worry about fetching the user entered values, Angular will take care that.

In this article we have discussed about setting a dynamic model and also about fetching those results. By using angular you can easily add or delete items from a list of blocks or from a grid.

Angular 2(+)Dynamic modelAdd

Related Info

1. Get Url parameter using Angular 2/5.

2. Share data between non related components - Angular 2/5.

Thursday, 22 March 2018

Catch all http errors using interceptors – Angular

AngularResponse InterceptorError handlinghttpClient

In this article we are going to discuss about creating a response interceptor using angular. Using this interceptor we can catch all http errors as well as success response in a single place. Since most of the applications will be using token to validate session, it is import to know API error status.

For example if we are getting 404 or 403 error from some API then we might trigger logout or need to indicate users about their session is invalid. We cannot go and check all the http request in all the service files, instead we will create a response interceptor and the same can be used for finding http status.

We can create interceptor to pass a common token to all http request as well. I have explained the same in my previous post. Please note this will work only angular 4.3 version and above.

Read more: - Set token to all htpp request.

Response interceptor


Check below complete code for response interceptor.


import { Injectable } from '@angular/core';
import {
    HttpInterceptor,
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpResponse,
    HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        return next.handle(request).do((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
                //success
                console.log('Success');
            }
        },
            (error: any) => {
                if (error instanceof HttpErrorResponse) {
                    if (error.status === 401) {
                        console.log('error found');
                    }
                    if (error.status === 404) {
                        console.log('Not found');
                    }
                    //etc
                }
            }
        )
    }
}

In the success block you will be getting all the success response from the API. If you want to handle some special case after getting result of some particular APIs, you can write those in the response block. In the above example I am checking the error status of http calls as well. Similarly you can add other status as well. We need to add ResponseInterceptor as part of our provider list in Module. Check below updated module code.

Module


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

// Components
import { AppComponent } from './app.component';

//interceptor
import { ResponseInterceptor } from './interceptor';


@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ResponseInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Here we have imported HTTP_INTERCEPTORS. In my previous post post I have explained about creating an interceptor to pass headers to all http calls. One thing to remember we need to use httpClient to make it work. If you want to add more interceptors in the module see below updated code.


providers: [AuthServices,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: SecurityTokenInterceptor,
      multi: true
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ResponseInterceptor,
      multi: true
    }
  ],

You can create multiple interceptors but you need to mention those in the module.

We can update response interceptor to invoke some methods in another service file. For example after getting 403 error from any of the API you may need to call the logout method in AuthService. Check below updated code.


import { Injectable } from '@angular/core';
import {
    HttpInterceptor,
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpResponse,
    HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import { AuthServices } from './services/authServices';

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {

    constructor(public auth: AuthServices) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        return next.handle(request).do((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
                //success
                console.log('Success');
            }
        },
            (error: any) => {
                if (error instanceof HttpErrorResponse) {
                    if (error.status === 401) {
                        this.auth.logout();
                        //any other action
                    }
                    if (error.status === 404) {
                        this.auth.openModelPopUp()
                        //any other action
                    }
                    //etc
                }
            }
        )
    }
}

Here we are calling logout method in the AuthService after getting 403 error. Similar way you can modify this to show a model popup or some other actions. If you want to know more about communicating between service files check this link and there are more ways to communicate with components - 7 method to share data between components. Clubbing these all logics we can implement a better application.

Read more: - Login authentication flow using auth guard.

In this article we have discussed about reading http response using an interceptor.

Angular 4.3(+)Angular 5Response InterceptorError handlinghttpClient

Related Info

1. Get Url parameter using Angular 2/5.

2. Share data between non related components - Angular 2/5.

Wednesday, 21 March 2018

Set headers for all http request using interceptor - Angular 5

Angular 4.3(+)Angular 5Interceptorcommon headerhttp

In this article we are going to discuss about setting a common headers for all http calls using angular interceptor concept. If you are using angular version below 4.3 then check my previous post to achieve this. For improving security of the application we need to pass a token to all http request so that the same can be validated in the backend and decide user session is valid or not. We can pass token to individual http request and also do the same using interceptor as well. Using interceptor we can pass token to all http request.

1. Set headers for single http request
2. Set headers for all http request using interceptor

1. Set headers for single http request


Let us check one use case where we need to pass headers for only some of the http request.


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';


@Injectable()
export class CommonService {

  _url: string;

  constructor(private http: HttpClient) { }

  sendData(item) {
    this._url = '/api/add/data';
    return this.http.post(this._url, item, {
      headers: { 'authTicket': '000001' }
    })
      .map((response: Response) => {
        return response;
      });
  }
}

Here we are passing headers to a particular http request. We can pass multiple headers as well. Check below code for that.


return this.http.post(this._url, item, {
    headers: { 'authTicket': '000001', 'otherToken': '90909' }
 })

If you want to know more about API calls check this link.

2. Set headers for all http request using interceptor


In the above example we have explained about passing header to single http calls. But in real time scenario we need to pass a token to all http request. Most of the applications follow the same as it is very important for application security. We cannot follow above approach for this, as our application may contains 100+ https request. We can use an interceptor for passing token to all http request. Check below interceptor code.

Interceptor


import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class SecurityTokenInterceptor implements HttpInterceptor {

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        request = request.clone({
            setHeaders: {
                AuthTicket: 'token_001'
            }
        })
        return next.handle(request);
    }
}

We are done with our interceptor, in the above example we have hardcoded the token as token_001. Before testing the result modify your module file like below. Don't forget to import HTTP_INTERCEPTORS.

Module


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

// Components
import { AppComponent } from './app.component';
import { GeneralComponent } from './dashboard/general/general.component';

// Services
import { CommonService } from './services/common.service';

//interceptor
import { SecurityTokenInterceptor } from './interceptor';


@NgModule({
  declarations: [
    AppComponent,
    GeneralComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: SecurityTokenInterceptor,
      multi: true
    }],
  bootstrap: [AppComponent]
})
export class AppModule { }

We are done. Now create some http request calls and test it. You can open the network tab and check headers are correctly passed or not.

In the above example we have hardcoded the token. But in real time you need to get it from a login API or some other apis depending on your project use case. Check below example to get a token from a service file.

Service file


import { Injectable } from '@angular/core';
@Injectable()
export class CommonService {

  token: string;

  getToken() {
    return this.token;
  }
  setToken(token) {
    this.token = token
  }
}

Here we are setting the token as soon we get from backend and you can get the sane anywhere by calling getToken method. Read more about setting and getting data from service here. Check updated interceptor code below.

Updated interceptor


import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { CommonService } from './services/common.service';

@Injectable()
export class SecurityTokenInterceptor implements HttpInterceptor {

    constructor(public auth: CommonService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        request = request.clone({
            setHeaders: {
                AuthTicket: this.auth.getToken()
            }
        })
        return next.handle(request);
    }
}

We have updated our interceptor to read data from a service file. Now create some http calls and test the result. I have written about authentication flow using auth guard.

Read more about here: - Login authentication flow using angular auth guard.

You can combine both article logic to implement a perfect login flow.

In this article we have discussed about creating an interceptor for passing a common header to all http calls.

Angular 4.3(+)Angular 5Interceptorcommon headerhttp

Related Info

1. Share data between Angular components - 7 methods.

2. Rating star component using Angular.

Monday, 19 March 2018

Send FormData using httpClient in Angular

Angular 2(+)Angular 4/5FormDatahttpClient

In this article we are going to discuss about sending data as FormData using httpClient in Angular. In my previous article I have explained about making an http call using httpClient. This is supported by Angular version 4.3 onwards. Any version below should use default http.

Let us check with an example for sending FormData. I have used FormData in my previous article for uploading a file and send data along with that. Check below code for sending FormData.

Component


<button class="btn" (click)="sendDataAsFormBody()">sendData</button>


import { Component } from '@angular/core';
import { CommonService } from '../../services/common.service';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {
  item: any;

  constructor(private commonService: CommonService) { }

  sendDataAsFormBody() {
    let fData: FormData = new FormData;
    fData.append("key1", 'Angular');
    fData.append("key2", 'JavaScript');
    fData.append("key3", 'React');

    this.commonService.sendData(fData).subscribe(
      data => {
        console.log(data);
      },
      error => {
        console.log(error);
      }
    )
  }
}

Here we are appending key value pair in FormData. You can loop it and add the data as well. Now check service file.

Service file


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';


@Injectable()
export class CommonService {

  _url: string;

  constructor(private http: HttpClient) { }

  sendData(item) {
    this._url = '/api/add/data';

    return this.http.post(this._url, item, {
      headers: { 'Content-type': 'application/x-www-form-urlencoded; charset=utf-8' }
    })
      .map((response: Response) => {
        return response;
      });

  }
}

Here I am passing headers as well along with http calls. If your version is below Angular 4.3, follow below code for passing header.


const headers = new Headers();
headers.set('authentication', 'auth ticket');
const options = new RequestOptions({ headers: headers });

We are done. In this article we have discussed about passing data as FormData using httpClient.

Angular 2(+)Angular 4/5FormDatahttpClient

Related Info

1. Angular 2/5 routing with simple examples.

2. Rating star component using Angular.

Friday, 16 March 2018

Http calls in Angular using HttpClient.

Angular 4.3(+)Angular 5HttpHttpClient

In this article we are going to discuss about making http calls using HttpClient. HttpClient is supported by Angular 4.3 version onwards. In my previous article I wrote about doing the same using http that can be used for angular version less than 4.3. Let us check the methods one by one.

1. Post
2. Get
3. Delete
4. Put

Post


Let us check HttpClient post call with one example. Create a component and invoke the method in the service file for making an API call, response will be returned to component.

Component


sendData() {
    this.item = {
      name: 'Angular',
      type: 'Framework',
      parent: 'Javascript'
    }

    this.commonService.sendData(this.item).subscribe(
      data => {
        console.log(data);
      },
      error => {
        console.log(error);
      }
    )
  }

CommonService is our service file, where we will be making the API call. Under data we will be getting the response and error in error block. Now let us check service code.

Service


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';


@Injectable()
export class CommonService {

  _url: string;

  constructor(private http: HttpClient) { }

  sendData(item) {
    this._url = '/api/add/data';
    return this.http.post(this._url, JSON.stringify(item))
      .map((response: Response) => {
        return response;
      });

  }
}

Here we have imported HttpClient and map from rxjs. To make it work you need to import HttpClientModule in the module file and also add under @NgModule/imports. Make sure you import after BrowserModule to make it work. I will share the module code as well at the end of the article. Now let us check the get call.

Get


Check the code below.

Component


getData() {
    this.commonService.getData().subscribe(
      data => {
        console.log(data);
      },
      error => {
        console.log(error);
      }
    )
  }

Service


getData() {
    this._url = '/api/get/data';
    return this.http.get(this._url)
      .map((response: Response) => {
        return response;
      })

  }

It is almost same except we are not passing the data.

Delete


It is also almost same, check below code.

Component


deleteData() {
    this.commonService.deleteData().subscribe(
      data => {
        console.log(data);
      },
      error => {
        console.log(error);
      }
    )
  }

Service


deleteData() {
    this._url = '/api/delete/id';
    return this.http.delete(this._url)
      .map((response: Response) => {
        return response;
      })
  }

Put


Put we use to update data, while post for adding new data.

Component


sendDataUsingPut() {
    this.item = {
      name: 'Angular',
      type: 'Framework',
      parent: 'Javascript'
    }

    this.commonService.sendDataUsingPut(this.item).subscribe(
      data => {
        console.log(data);
      },
      error => {
        console.log(error);
      }
    )

  }

Service


sendDataUsingPut(item) {
    this._url = '/api/add/data';
    return this.http.post(this._url, JSON.stringify(item))
      .map((response: Response) => {
        return response;
      });
  }

Now check our module code.

Module



import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

//Services
import { CommonService } from './services/common.service';

@NgModule({
  declarations: [
    AppComponent,
    GeneralComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
  ],
  providers: [CommonService],
  bootstrap: [AppComponent]
})
export class AppModule { }

We have imported HttpClientModule and also added CommonService in provider.

We are done. In this article we have discussed about making an API call using HttpClient. This is supported by Angular 4.3 version onwards.

Angular 4.3(+)Angular 5HttpHttpClient

Related Info

1. Angular 2/5 routing with simple examples.

2. Rating star component using Angular.

Monday, 12 March 2018

Different ways to add css in an Angular component.

Angular 2(+)CSSComponent styling

Different ways we can add styles in Angular application. Let us check those one by one.

1. Adding style url into the component.
2. Adding css inside the component.
3. Adding css along with template.
4. Inline style.

1. Adding style url into the component.


This is one of the common way to include a css file into your component. Use sass (css preprocessor) to build your angular application. It will give proper grip on your css. Check below component code for including a style url.


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

}

Similar way you include more than one css. Check below code for that.


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss', '../anotherStyle.scss']
})
export class GeneralComponent {

}

2. Adding css inside the component.


Another way is that you can add css directly inside the component. You can use this especially when your components required more css manipulation for some conditions. Check below code for better understanding.


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styles: [
    `  
    .content{
        color:red;
      }   
    `
  ]
})
export class GeneralComponent {

}

Using Angular you can add or remove class/style conditionally, read here for more info: - Conditionally add class using Angular - 5 methods.

3. Add style along with template.


This is another way of adding css into your component. In this case we are adding css along with templates. Check below code for more info.


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  template: `
    
  <style>
    .content {color :red;}
    .active {color:blue;}
  </style>
  <div class="content">Test</div>
  
  `,
})
export class GeneralComponent {

}

You can add/remove a class by clicking a dynamic element using Angular, check this link for more info: - Add or remove active class on click.

4. Inline style


This is one of the old ways that people may not suggest as a good approach. Here we are adding inline css along with template html. Check below code.


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  template: '<div style="color:red">Test</div>',
})
export class GeneralComponent {

}

As we know already css will give priority for last rendered. For example check below code.


.sampleStyle {
    color:red;
    color:blue;
}

In this example it will take color as blue.

If you are using Angular CLI, you can add external css and your main style file in this cli. For example check below code.


"styles": [
        "../node_modules/bootstrap/dist/css/bootstrap.css",
        "styles.scss"
      ],

Here I have added bootstrap and style.scss. As a best practice, in style.scss you can import all your css files.

In this article we have discussed about different ways for adding styles into an Angular component.

Angular 2(+)CSSComponent styling

Related Info

1. Angular 2/5 routing with simple examples.

2. Responsive image using HTML-5 srcset and Angular.

3. Rating star component using Angular.

Friday, 9 March 2018

Responsive image using HTML-5 srcset and Angular.

Html 5srcsetAngular 2/5Responsive image

In this article I will be discussing about making an image responsive using latest html 5 attributes. We will integrate the same with Angular for better usage. Using srcset attribute we can set more than one images in the html itself and browser will decide which should load. As a result user can see best quality images depends on their browser size. Along with srcset you can add different size as well. Basically you can avoid using media queries and other codes to make it responsive rather you can set the images and let browser choose the best one. Let us check with an example first.

Image srcset



<img srcset="sample-image1-320w.jpg 320w,
            sample-image2-480w.jpg 480w,
            sample-image3-800w.jpg 800w" 
      src="default-image-800w.jpg" alt="Responsive image">

Here you can see that I have added 3 images and one default image, basically all are same images with different resolution and width. Here 320w means 320 width, instead of w you can use x as well. Similarly you can add the size as well.


<img srcset="sample-image1-320w.jpg 320w,
            sample-image2-480w.jpg 480w,
            sample-image3-800w.jpg 800w" 
      sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px" 
       src="default-image-800w.jpg" alt="Responsive image">

So in this case browser will choose the image and size which suits best for the current view.

web

If you still want to use media query then try with html 5 picture. Check below code.


<picture>
  <source media="(max-width: 799px)" srcset="sample-image1.jpg">
  <source media="(min-width: 800px)" srcset="sample-image2.jpg">
  <img src="defult.jpg" alt="Responsive image">
</picture>

Now let us check how we can use Angular here. Html 5 has lot of powerful features which will really help you to build a good Angular application. For example in my previous article I have created an autocomplete feature, one by using Angular from scratch and other one with Html 5 + Angular. You can check those here: - AutoComplete using Angular from scratch and Autocomplete using HTML 5 + Angular.

Image srcset + Angular


Angular provides many ways to add a class/styles conditionally. By using those features you can set the images and size conditionally.

html


<img srcset="{{imageMap.toString()}}" sizes="{{imageSize.toString()}}" 
     src="default-image-800w.jpg" alt="Responsive image">

component


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

  imageMap: any[];
  imageSize: any[];
  
  constructor() {
    this.imageMap = [
      "sample-image1-320w.jpg 320w",
      "sample-image2-480w.jpg 480w",
      "sample-image3-800w.jpg 800w"
    ];

    this.imageSize = [
      "(max-width: 320px) 280px",
      "(max-width: 480px) 440px",
      "800px"
    ]
  }
}

Here we have added the image path and size in the component and rendering into the html. There are many ways to add a class/styles conditionally, check these links for that : - 5 different ways to add class/styles and conditionally add class using angular.

Instead of adding this into the component you can create a service file and get the values on demand in any component as well. Read more about those here: - Get data from service file and Share data between Angular components - 7 methods

We are done. In this article we have discussed about creating a responsive image using Html 5 + Angular.

Html 5srcsetAngular 2/5Responsive image

Related Info

1. Angular 2/5 routing with simple examples.

2. Login authentication flow using angular auth guard - Angular 5

Wednesday, 7 March 2018

Angular autocomplete using HTML 5 - Angular 2/5

Angular 2/5Auto CompleteHTML 5Datalist

Here I am going to implement an auto complete feature using HTML 5 tag datalist along with using Angular. Advantage of using this tag is that no need to write any logic into your ts(js) file. In my previous article I have explained about creating an autocomplete using angular 2/5 from scratch. Let us check the same using html5.

AutoComplete using HTML5 + Angular


Html


<div class="typeHead">
    <input type="text" list="countries" name="country" [(ngModel)]='selected' (change)="selectCountryName(selected)" />
    <datalist id="countries">
        <select>
            <option *ngFor="let c of countrylist" [value]="c.name"></option>
        </select>
    </datalist>
</div>

Angular role is very less here, autocomplete feature is taken care by html 5 datalist. Angular is used here only to set and get the selected values. Check below component code as well.

Component


import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'auto-complete',
    templateUrl: '../autoComplete/autoComplete.html',
})

export class autoCompleteComponent {
    countrylist: any[];
    selected: string = "";

    ngOnInit() {
        this.countrylist = [
            { "name": "Afghanistan", "code": "AF" },
            { "name": "Ă…land Islands", "code": "AX" },
            { "name": "Albania", "code": "AL" },
            { "name": "Algeria", "code": "DZ" },
            { "name": "American Samoa", "code": "AS" },
            { "name": "AndorrA", "code": "AD" },
            { "name": "Angola", "code": "AO" },
            { "name": "Anguilla", "code": "AI" },
            { "name": "Antarctica", "code": "AQ" },
            { "name": "Antigua and Barbuda", "code": "AG" },
            { "name": "Argentina", "code": "AR" },
            { "name": "Armenia", "code": "AM" },
            { "name": "Aruba", "code": "AW" },
            { "name": "Australia", "code": "AU" },
            { "name": "Austria", "code": "AT" },
            { "name": "Azerbaijan", "code": "AZ" },
            { "name": "Bahamas", "code": "BS" },
            { "name": "Bahrain", "code": "BH" },
            { "name": "Bangladesh", "code": "BD" },
            { "name": "Barbados", "code": "BB" }
        ]
    }
    selectCountryName(name) {
        console.log(name);
        console.log(this.selected);
    }
}

selectCountryName is the method where we are getting the selected country list. You can console the output as console.log (name) or console.log (this.selected). In the above example you may notice that I have added a <select></select> tag in-between datalist. This will help you to show a select box if any old browser doesn't support HTML 5 datalist. If you are facing any compatibility issues on any older Brower, you can include datalist - polyfill as well.

If you don't want to use this solution you can check this link : - Autocomplete using angular from scratch.

In this article we have discussed about creating an autocomplete feature using HTML 5 + Angular.

Angular 2/5Auto CompleteHTML 5Datalist

Related Info

1. Http calls in Angular with simple examples.

2. 5 different ways for conditionally adding class - Angular.

3. Angular 2/4 routing with simple examples.

4. Login authentication flow using angular auth guard - Angular 5

Monday, 5 March 2018

Angular auto focus for input box - Angular

AngularAuto FocusAuto focus directive

In this article we will be discussing about setting an autofocus for a text box and also setting focus on a click. Let us check with some examples.

1. Auto focus on textbox using directive.
2. Set focus on text box on click.
3. Auto focus on textbox without using a directive.

1. Auto focus on textbox using directive


Especially while dealing with forms you may need to set default focus on some fields. We are going to create a simple angular directive to achieve this. Once directive is ready we can assign a Boolean value directly to the html. Let us check directive code first.

Directive


import { OnInit, ElementRef, Renderer, Input, Directive } from '@angular/core';

@Directive({ selector: '[focuMe]' })
export class FocusDirective implements OnInit {

    @Input('focuMe') isFocused: boolean;

    constructor(private hostElement: ElementRef, private renderer: Renderer) { }

    ngOnInit() {
        if (this.isFocused) {
            this.renderer.invokeElementMethod(this.hostElement.nativeElement, 'focus');
        }
    }
}

Angular 8(+)

If you are using Angular 8(+) in your application, then please consider below changes. Because Renderer is deprecated and now we have to use Renderer 2. invokeElementMethod is not available in Renderer 2. Update the directive code like below.


if (this.isFocused) {
   this.hostElement.nativeElement.focus();
}

Our directive is ready. focuMe is the name of the directive selector. Don't forget to import the dependencies OnInit, ElementRef, Renderer, Input and Directive. Also update the module by adding directive name (FocusDirective) under module declarations. Now check the html for the same.


<input type="text" [(ngModel)]="term1" [focuMe]="true">

You can assign true or false, also you can set the flag in your component as well.

html


<input type="text" [(ngModel)]="term2" [focuMe]="isFocus">

component


import { Component } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

  isFocus: boolean = true;
}

Complete directive code for Angular 8(+) application

import {OnInit, ElementRef, Input, Directive} from '@angular/core';

@Directive({selector: '[focuMe]'})
export class FocusDirective implements OnInit {

  @Input('focuMe') isFocused: boolean;

  constructor(private hostElement: ElementRef) {
  }

  ngOnInit() {
    if (this.isFocused) {
      this.hostElement.nativeElement.focus();
    }
  }
}


We are done, our auto focus angular directive is ready to use.

2. Set focus on text box on click.


In the above example we have created a simple directive to set auto focus on text box. Now check another scenario of adding a focus on click. Check the below html code first.


<button (click)="setFocus()">Set Focus</button>
<input type="text" [(ngModel)]="term2" #inputBox>

Please not we have added #inputBox along with the text box. Same will be using to set the focus. Check the component code now.


import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

  @ViewChild("inputBox") _el: ElementRef;

  setFocus() {
    this._el.nativeElement.focus();
  }
}

On click of setFocus method focus will set to the text box. Same code you can use for setting the autofocus as well. Let us check that code as well.

3. Auto focus on textbox without using a directive.



<input type="text" [(ngModel)]="term2" #inputBox>


import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-general',
  templateUrl: './general.component.html',
  styleUrls: ['./general.component.scss']
})
export class GeneralComponent {

  @ViewChild("inputBox") _el: ElementRef;

  setFocus() {
    this._el.nativeElement.focus();
  }
  ngAfterViewInit() {
    this._el.nativeElement.focus();
  }
}

Here we are setting the autofocus on ngAfterViewInit angular life cycle.

We are done. In this article I have explained about setting an auto focus with and without using a directive and also setting focus on click.

AngularAuto FocusAuto focus directive

Related Info

1. 3 simple ways to share data through angular route.

2. Get Url parameter using Angular.

3. Truncate file name without hiding the extension using Angular Pipe.

4. Conditionally add class using Angular - 5 methods