Reputation: 8703
I'd like to setup a <select>
with a default <option>
using HTML, and populating the rest of the <select>
with two way binding to my model.
HTML:
<select class="form-control" required
[(ngModel)]="model.product"
ngControl="product">
<option value="">Select a product</option>
<option *ngFor="#product of products" [value]="product">{{product}}</option>
</select>
Model:
products: string[] = [
'Foo',
'Bar'
];
What's happening now is my the select is binding to the model, which is:
model: Entry = new Entry();
So, there's no default value in the product
property, thus the <select>
binds to nothing. I mean, this is working as expected.
I'm trying to figure out how to get a default value to show up in the <select>
though, and I'd like to do that without hard coding a UI value in my model and defaulting that in a new instance of my model. Does Angular 2 have a way to deal with this?
Edit:
The result HTML should look like:
<select>
<option value>Select a product</option>
<option value="foo">Foo</option>
<option value="bar">Bar</option>
</select>
Upvotes: 26
Views: 29211
Reputation: 1953
You are approaching in right direction. One thing that needs to consider is that null value of model is being compared with empty string value of default option. So if you compare and set null value of your default display text then it'll work fine. I have set as above and it's working for me !
<select class="form-control"
required
[(ngModel)]="model.product"
ngControl="product">
<option value="model.product === null ? null : ''">
Select a product
</option>
<option *ngFor="#product of products"
[value]="product">{{product}}</option>
</select>
Upvotes: 0
Reputation: 521
I have done it this way and it works for me:
<select name="Products" #Products="ngModel" [(ngModel)]="products">
<option [ngValue]="products">-- Select product --</option>
<option *ngFor="let p of productsList" [ngValue]="p">{{p.name}}</option>
</select>
[ngValue]="products"
indicates to [(ngModel)]="products"
.
Before this I had <option value="">-- Select product --</option>
but then it renderd to: blank option, -- Select product -- and list of my products.
Upvotes: 11
Reputation: 2394
I exactly had the same issue, we can just bind the ngModel to the value :
<option *ngFor="#product of products" [value]="model.product">{{product}}</option>
Upvotes: 0
Reputation: 190
On beta 14 (see: Angula2-beta.14 Changlog), angular adds the support for Object in select tags:
<select class="form-control" required [(ngModel)]="model.product">
<option *ngFor="#prod of products"
[ngValue]="prod">
{{prod.name}}
</option>
</select>
instead of [value]
, you can use [ngValue]
to bind an object to ngModel
in select tag.
You can see a example on Plunker with default value.
The attribute selected
isn't working, I'm trying to fix this on my project with some workaround!
Hope that can be useful.
Upvotes: 2
Reputation: 15279
In fact, you could create Directive
to append default option and handle two-way binding:
import {Directive, ElementRef, Input, OnInit, Output, EventEmitter, HostListener} from 'angular2/core';
/**
* <select [ngSelect]="'select number...'" [(ngSelectModel)]="model" >
* <option *ngFor="#item of ['1', '2', '3']" [value]="item">{{item}}</option>
* </select>
*/
@Directive({
selector: '[ngSelect]'
})
export class DefaultOption implements OnInit
{
private _el:HTMLSelectElement;
@Input('ngSelect')
private defaultText:string;
@Output()
private ngSelectModelChange:EventEmitter = new EventEmitter();
private _ngSelectModel:any;
constructor(el:ElementRef)
{
this._el = el.nativeElement;
}
@Input()
public get ngSelectModel():any
{
return this._ngSelectModel;
}
public set ngSelectModel(value:any)
{
this._ngSelectModel = value;
if (this.ngSelectModel !== undefined)
{
this._el.value = this.ngSelectModel;
}
else
{
this._el.value = '';
}
}
protected ngOnInit():any
{
var element:HTMLOptionElement = document.createElement('option');
element.text = this.defaultText;
element.value = '';
this._el.insertBefore(element, this._el.firstChild);
//delayed execution
setTimeout(()=>
{
if (this.ngSelectModel !== undefined)
{
this._el.value = this.ngSelectModel;
}
else
{
this._el.value = '';
}
}, 0);
}
@HostListener('change', ['$event.target.value'])
private onInput(value):void
{
if(value !== '')
{
this.ngSelectModelChange.emit(value);
}
else
{
this.ngSelectModelChange.emit(undefined);
}
}
}
Upvotes: 3
Reputation: 364727
I don't think Angular has a way to deal with this. You'll have to do some work:
<select class="form-control" required [(ngModel)]="model.product">
<option *ngFor="#product of [defaultStr].concat(products)"
[value]="product === defaultStr ? null : product">
{{product}}
</option>
</select>
defaultStr = 'Select a product';
model = { product: null };
products: string[] = [
'Foo',
'Bar'
];
Since you are using NgModel to bind the selected value, you have to set the bound property to the default value initially, which is null
, otherwise that option won't be selected by default:
model = { product: null };
With null
, I noticed that the HTML is
<option value="null">Select a product</option>
So, you may prefer to use an empty string ''
instead of null
:
[value]="product === defaultStr ? '' : product"
model = { product: '' };
Then the HTML is
<option value="">Select a product</option>
Upvotes: 13