Earlier I posted about the differences between AngularJS 1.x and Angular 2 in which I tried to explain how things changed with respect to Angular 2.In this post, we’ll find out how to bind select dropdown list in Angular 2.
UPDATE(6-Dec-2016): Updated to Angular 2 RTM release.
Also read,
- Angular 5 is out. Create an Angular 5 app with Visual Studio 2017
- Upgrade Angular 4 app to Angular 5 with Visual Studio 2017
- How to create an Angular 4 app with Visual Studio 2017
- How to bind Click event in Angular 2
- Cascading DropDown List with ASP.NET Core WEB API and Angular 2
Bind select dropdown list in Angular 2
If you want to learn all of Angular, I want to personally recommend ng-book as the single-best resource out there. You can get a copy here.
For the demo, I created a sample Angular 2 application using TypeScript which binds the country list collection to select dropdown list. Below image shows, the structure of Angular 2 application. Read TypeScript Interview Questions to get started with TypeScript.
In Angular 2, controllers and $scope are replaced with “Components” and you think everything in terms of classes. Now, let’s see each file’s code and its purpose.
- country.ts: This file has a simple class called “Country” with 2 properties id and name.
- countrylistcomponent.ts: This file contains code for defining a component and template used to render HTML. The Component adds the metadata to the class.
- countrylistcomponent.html: This file has HTML code to render select dropdown list.
- app.ts: This file contains code to of Angular 2 root module. Every angular 2 application is having a root module. This was introduced in the RC 5 release.
- main.ts: This file contains code to bootstrap angular 2 in our application.
- config.js: This file contains code to load angular 2 and all its required packages.
Code Walk-through
Country.ts
Nothing fancy here. Simple class with 2 properties.
export class Country { constructor(public id: number, public name: string) { } }
CountryListComponent.ts
This file has class CountryListComponent
which creates an array of Country
class and populate the data. Angular apps are modular and Angular itself is modular. So to use @Component
directive, we first need to import the library. The very first statement imports it and similarly to use Country
class within this file, we also import it. The @Component
annotation adds the metadata to the class.
import {Component, NgModule} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' import { Country } from './country'; @Component({ selector: 'my-country-list', templateUrl: 'app/countrylistcomponent.html' }) export class CountryListComponent { selectedCountry:Country = new Country(2, 'India'); countries = [ new Country(1, 'USA' ), new Country(2, 'India' ), new Country(3, 'Australia' ), new Country(4, 'Brazil') ]; }
The @Component
metadata object has two fields, a selector and a template.
- The selector specifies a selector for an HTML element that represents the component.
- The template tells Angular how to render this component’s view. There can be a URL of HTML file or you can also put HTML here. For this demo, I put the URL pointing to a HTML file.
There is also a class named CountryListComponent, which is your component class. And within this class, initialization of countries array is done. And here the Country class is also used for populating country.
CountryListComponent.html
This is the file which specified in the templateURL for @Component
directive. In this file, there is a select HTML element and within the option, *ngFor
structural directive is used. With Angular 1.x, ng-repeat
was used for looping purpose, but things changed in Angular 2. Let’s visit all new changes with respect to the below code.
ng-repeat
is replaced with*ngFor
- Asterisk(*) sign is used as prefix for structural directives
- With
ng-repeat
the syntax iscountry in countries
where with*ngFor
it islet country of countries.
.in
is replaced withof
. - camelCase syntax is used.
- In Angular 2, local variables are defined using hash(#) prefix.
<select> <option *ngFor="let country of countries" value= {{country.id}}> {{country.name}} </option> </select>
app.ts
Every Angular app has a root module class. By convention, it’s a class called AppModule
.
- First, import all the required things.
- The
@NgModule
decorator defines the metadata for the module.BrowserModule
registers critical application service providers. It also includes common directives likeNgIf
andNgFor
which become immediately visible and usable in any of this modules component templates.FormsModule
is required for thengModel
directive. - The
declarations
list identifies the application’s only component, the root component, the top of this app’s rather bare component tree. we can list the components, directives, and pipes that are part of the module in thedeclarations
array. - Import other modules by listing them in the
imports
array. - The
bootstrap
property should have the name of root component that should be used as bootstrap entry points for the application.
//our root app component import {Component, NgModule} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' import { FormsModule } from '@angular/forms'; import { CountryListComponent } from './countrylistcomponent'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ CountryListComponent ], bootstrap: [ CountryListComponent ] }) export class AppModule {}
Please read following post to understand more about NgModule.
Main.ts
This file has code to bootstrap Angular 2 in our application. Remember ng-app
is no longer available. The only way to bootstrap Angular 2 is via code. We launch the application by bootstrapping the AppModule
in the main.ts file. We need to import two things here,
- Angular’s browser bootstrap function
- The application root/parent module, which is
Appmodule
. This is new in Angular 2. Every Angular 2 application is now having a root module.
And then call bootstrap
with AppModule
//main entry point import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {AppModule} from './app'; platformBrowserDynamic().bootstrapModule(AppModule)
This code can also be moved to CountryListComponent.ts
but putting it in a separate file is a proper way to structure any Angular application. As App bootstrapping is a separate concern, and we should not mix it with other code.
Index.html
Finally, index.html where actual magic happens. All the required dependencies are refereed. And I am using SystemJs to load the application and modules. You can read about how to configure it here. The config.js file contains all the code to load angular 2 and its packages. And also the selector defined in the component is placed in this file [line number: 19].
<!DOCTYPE html> <html> <head> <base href="." /> <title>Angular 2 Bind select list demo</title> <link rel="stylesheet" href="style.css" /> <script src="https://unpkg.com/zone.js/dist/zone.js"></script> <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script> <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script> <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script> <script src="config.js"></script> <script> System.import('app') .catch(console.error.bind(console)); </script> </head> <body> <h2>Angular 2 Bind select list demo</h2> <my-country-list>Loading....</my-country-list> </body> </html>
In the CountryListComponent
class, there is a property defined named selectedCountry and it is set to a new Country
Class object. So now, you can use this property to show the selected country on load. All you need to use is [(ngModel)]
directive. Notice, the syntax is also changed for two-way binding in Angular 2.
<select [(ngModel)]="selectedCountry.id"> <option *ngFor="let country of countries" value= {{country.id}}> {{country.name}} </option> </select>
Here, the selected country’s id is available in the selectedCountry.id
(thanks to two-way data binding), but the selected country’s name is not available as only the id property gets updated. Let’s modify to code to update the complete object. Firstly, update HTML to include the dropdown change event.
<select (change)="onSelect($event.target.value)" [(ngModel)]="selectedCountry.id"> <option *ngFor="let country of countries" value= {{country.id}}> {{country.name}} </option> </select> <br/> Selected Country ID: {{selectedCountry.id}} & Name: {{selectedCountry.name}}
Next, in CountryListComponent.ts, define an onSelect method which handles when a drop down option is selected which in turn updates the selectedCountry object.
onSelect(countryId) { this.selectedCountry = null; for (var i = 0; i < this.countries.length; i++) { if (this.countries[i].id == countryId) { this.selectedCountry = this.countries[i]; } } }
You can also check all the code and demo at Plunker [Demo is not working currently as Plunker is breaking while initializing the Angular app].
If you are looking for Angular 4 or 5 based solution, please visit here.
I also enhanced this Angular 2 app and shown how to create Cascading DropDown List using Angular 2 . If you are looking to bind radio button list, then read this post.
Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.
I am working on a project where i am using mongodb as a backend and angular2 for front end. I have two collections in db as Country{id, countryname} and state{id, statename} I want to find all the states depending on the country , I tried to write a code using $lookup but getting nothing. Also i need to use these two collections in an angular application for cascading dropdown. If i Select “India” only “States” in india should populate.I am new to mongodb. Plz help
Thanks. It helped me.
I went to the plunker demo and it just loads?
Not loads just says loading…
Sorry to read that, but it seems there is some issue with the plunker itself. It’s not able to load all the dependencies. I should fix it up as soon as plunker is working.
Hello, thank you for this post, is very important. I have the problem with this function
selectedClient: Client = new Client(”);
onSelect(clientid) {
this.selectedClient = null;
for (let i = 0; i < this.client.length; i++) {
if (this.client[i].client_id === clientid) {
this.selectedClient = this.client[i];
}
console.log(this.selectedClient) // selectedClient execute for any client, and in display the value are shaken. For example, I have 3 client client1{1,'Tom','USA','123'} , Client2: {2,'Au','It','123456'},Client3: {3,'test','Gr','3265'}.
}
Whene I select Client1, in console show 3console form this data mix. Can you help me?
Code looks okay but a quick observation. Try == instead of === while comparing inside the for loop.
hi how to assign selected value ie country.id to a variable ?
Thanks
Thank you sharing this.. it help me a lot to understand..
Try this solution: https://plnkr.co/edit/WmpSuwugG77ONlBP1MvW?p=preview
Apologies, I forgot to link to it:
https://plnkr.co/edit/WmpSuwugG77ONlBP1MvW?p=preview
https://valor-software.com/ng2-select/
Bob,
Sorry for the long delay, the post is updated to include solution of your issue.
In the Plunker you link to I added a label to mirror the selection but it doesn’t work if I try to mirror the country name. It only works with the country id. Why is that?