The ngFor directive is a successor of ng-repeat directive in AngularJS. You can attach the ngFor directive to an element like this,
<div *ngFor='let bird of arrBirds'>
<div>{{ bird.name }}</div>
</div>
The value bird inside *ngFor directive is a variable of an array named arrBirds, which I have declared in my component class. The array has a property called name with some values it.
export class AppComponent {
arrBirds: any [] = [
{ name: 'Bells Sparrow' },
{ name: 'Mourning Dove'},
{ name: 'Bald Eagle' }
];
ngOnInit () {
);
}
}
The output, in your browser, would be,
Bells Sparrow
Mourning Dove
Bald Eagle
Now, let’s see how we can add dynamic data (extracted from a Web API method) to an array and attach the array to a SELECT Dropdown list using the ngFor directive.
Create a Table in SQL Server
We need a database for the data. Create a table in SQL Server and few data to it.
CREATE TABLE [dbo].[Books]( [BookID] [int] IDENTITY(1,1) NOT NULL, [BookName] [varchar](50) NULL, PRIMARY KEY CLUSTERED ( [BookID] ASC ) ) ON [PRIMARY]
Web API (using MVC 4)
Next, create a Web API in Asp.Net. I have MVC 4 installed in my computer. You can use any other version.
using System; namespace BooksApp.Models { public class Books { public string BookName { get; set; } } }
Imports System.Web Namespace BooksApp.Models Public Class Books Public Property BookName() As String Get Return m_BookName End Get Set(value As String) m_BookName = value End Set End Property Private m_BookName As String End Class End Namespace
Web API Controller
The Controller in this project has a single public method called Get(), which will handle the http request and return the list of books to the calling application.
using System; using System.Collections.Generic; using System.Net; using System.Net.http; using System.Web.http; using BooksApp.Models; using System.Data.SqlClient; namespace BooksApp.Controllers { public class BooksController : ApiController { // LIST OBJECT WILL HOLD AND RETURN A LIST OF BOOKS. List<Books> MyBooks = new List<Books>(); // THE "GET" METHOD WILL RETURN ALL THE BOOKS IN THE TABLE. public IEnumerable<Books> Get() { string sConnString = "Data Source=DNA;Persist Security Info=False;" + "Initial Catalog=DNA_Classified;User Id=sa;Password=;Connect Timeout=30;"; SqlConnection myConn = new SqlConnection(sConnString); // THE SQL QUERY TO GET THE BOOKS FROM THE TABLE. SqlCommand objComm = new SqlCommand("SELECT *FROM dbo.Books", myConn); myConn.Open(); SqlDataReader reader = objComm.ExecuteReader(); // POPULATE THE LIST WITH DATA. while (reader.Read()) { MyBooks.Add(new Books { BookName = reader["BookName"].ToString() }); } myConn.Close(); return MyBooks; // RETURN THE LIST. } } }
Option Explicit On Imports System.Net.http Imports System.Web.http Imports System.Data.SqlClient Imports BooksApp.BooksApp.Models Namespace BooksApp Public Class BooksController Inherits ApiController ' LIST OBJECT WILL HOLD AND RETURN A LIST OF BOOKS. Dim MyBooks As New List(Of Books)() ' THE "GET" METHOD WILL RETURN ALL THE BOOKS IN THE TABLE. Public Function [Get]() As IEnumerable(Of Books) Dim sConnString As String = "Data Source=DNA;Persist Security Info=False;" & _ "Initial Catalog=DNA_Classified;User Id=sa;Password=;Connect Timeout=30;" Dim myConn As New SqlConnection(sConnString) ' THE SQL QUERY TO GET THE BOOKS FROM THE TABLE. Dim objComm As New SqlCommand("SELECT *FROM dbo.Books", myConn) myConn.Open() Dim reader As SqlDataReader = objComm.ExecuteReader() ' POPULATE THE LIST WITH DATA. While reader.Read() MyBooks.Add(New Books() With { _ .BookName = reader("BookName").ToString() }) End While myConn.Close() Return MyBooks ' FINALLY, RETURN THE LIST. End Function End Class End Namespace
Run the API.
Create Angular 4 Project
Now, create a project using Angular CLI (Command Line Interface). Open the command prompt and go to the folder where you want to create the project and enter,
ng new angular-ngfor-example
Next, go to the folder.
cd angular-ngfor-example
Finally, launch the server.
ng serve --open
Import HttpClientModule to the Project
To consume the Web API services in my Angular app, I am using the new HttpClient Service in my application. This service was first introduced in Angular 4.3 and is included in the HttpClientModule. Therefore, I’ll first import the HttpClientModule in the app.module.ts file.
Along with HttpClientModule, I am also importing the FormModule. I have highlighted both the modules in the code below.
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/https'; import { FormsModule } from '@angular/forms'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
The FormModule in the above code, is necessary since I am using the ngModel directive for one way binding. See the application template (the markup) below.
After we have created the module, its time create the component.
The Application Component
Open app.component.ts file. Here we’ll import the HttpClient class, which will provide the necessary functions and properties to initiate http request and responses. I’ll import HttpErrorResponse class to handle errors. Finally, I’ll declare an array here, which will hold data extracted from the http response and attach the array to the SELECT Dropdown list using ngFor directive.
import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/https'; import { HttpErrorResponse } from '@angular/common/https/src/response'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Angular 4 ngFor Example with SELECT Dropdown List'; constructor (private httpService: HttpClient) { } myBooks: string []; selected = null; ngOnInit () { this.httpService.get('http://localhost:43487/api/books/').subscribe( data => { this.myBooks = data as string []; // FILL THE ARRAY WITH DATA. }, (err: HttpErrorResponse) => { console.log (err.message); } ); } }
I’ll now add a SELECT Dropdown list element to my project template and attach the array (myBooks) to the element using ngFor directive.
<div style="text-align:center;width:500px;"> <h1> {{title}}! </h1> <div style="float:left;padding:10px;margin:0 auto;" *ngIf="myBooks"> <select [(ngModel)]="selected"> <option *ngFor="let book of myBooks" [(ngValue)]="book.BookName">{{book.BookName}}</option> </select> <p>{{ selected }}</p> </div> </div>
You can style it if you want using inline CSS or add some classes and properties in the app.component.css file.
Other than ngFor, I am using three other directives in my application template. The first is *ngIf directive to check if myBooks exists. The second directive is ngModel, to bind the selected value (in the SELECT Dropdown list) with a <p> element.
The third and fourth directives are the ngFor and ngValue with the <option> tag.
<option *ngFor="let book of myBooks" [(ngValue)]="book.BookName">{{book.BookName}}</option>
The ngValue directive is an alternative to the value property. I could have used the value to show the items in the Dropdown list. It works fine.
<option *ngFor="let book of myBooks" value="book.BookName">{{book.BookName}}</option>
However, with the value property, I cannot bind the selected value (using ngModel) to the <p> element properly. The ngValue directive solves the problem.
This post here may also be useful.
That’s it. I have explained about Error Handling in Angular 4 in my previous post, since I have applied error handler in the component above.
Well, binding dynamic data (using Web API), to a SELECT Dropdown list in Angular 4 is very simple. You can use a JSON array for your exmaple. I have shared a Similar example:> before and you should read it too.
I have also explained two simple examples here on how to use Angular 4 ngFor directive with an HTML element to show data, extracted from an array. The ngFor loops through a list of items in array and displays it.
Along with this, I have explained one way binding using ngModel directive. I have shown you how to attach the directive with the SELECT element and display the selected value to another element.