Issue with <select> tag in angular5 - html

I am facing an issue with <select> tag in angular 5. I have an array of objects. Lets say
public countryList = [ {
'name': 'xxx',
'capital': 'abc'
}, {
'name': 'yyy',
'capital': 'efg'
}, {
'name': 'zzz',
'capital': 'pqr'
},
];
and in html
<select placeholder="Select" (change)="displayFunction()">
<option class="auto-height" *ngFor="let country of countryList; let id=index"
[disabled]="id === (country .length)-1" [value]="country .name">
<div class="stop-container">
<b>{{country.name}}</b>
<p>{{country.capital}}</p>
</div>
</option>
The issue comes when we select any option in the dropdown all the values listed inside<option> is shown as the slected value. I need only name as selected value. Any solution for this? I am getting output given below. What is need is XXX instead of XXX abc

You can't have a div inside your option. If you want to have some special formatting inside a dropdown you have to recreate the dropdown with JS (or use, for example, angular material)
So to only display the name, you can do the following:
<select placeholder="Select" (change)="displayFunction()">
<option class="auto-height" *ngFor="let country of countryList; let id=index"
[disabled]="id === (country .length)-1" [value]="country .name">
{{country.name}}
</option>
</select>

<select [(ngModel)]="selectedDevice" placeholder="Select" (change)="displayFunction($event.target.value)">
<option class="auto-height" *ngFor="let country of countryList; let id=index"
[disabled]="id === (country.length)-1" [value]="country.name">
<div class="stop-container">
<b>{{country.name}}</b>
<p *ngIf="selectedDevice!=country.name">{{country.capital}}</p>
</div>
</option>
</select>
Replace this line

Related

Select doesn't display patched value

I have a form with a form control currency.
A currency object looks like this {id: string; symbol: string};
On init, the currency select iterates over an array of currencies;
After a condition is verified I need to patch a currency object to my select
const currency = {id: '2', symbol: 'CAD'}
this.currency.patchValue(currency);
console.log(this.currency.value);
the output is correct: {id: '2', symbol: 'CAD'}, but there is no selected option in my dropdown
<select class="generalDropdown currencies" formControlName="currency">
<option value=null disabled>CUR</option>
<option *ngFor="let currency of allCurrencies" [value]="currency.id"> {{currency.symbol}}
</option>
</select>
Initially you are assigning [value]="currency.id" to select element. But when you are patching value to formControl we are setting object value, due to which select not showing bind value. You can fix the issue by patch currencyId instead of patching whole object.
const currency = {id: '2', symbol: 'CAD'}
this.currency.patchValue(currency.id);
OR
You need to assign whole object to ngValue. Then to match object reference we need to use compareWith function along with select.
<select class="generalDropdown currencies" [compareWith]="compareFn" formControlName="currency">
<option value=null disabled>CUR</option>
<option *ngFor="let currency of allCurrencies" [value]="currency"> {{currency.symbol}}
</option>
</select>
component.ts
compareFn(c1: any, c2: any): boolean {
return c1 && c2 &&( c1.id === c2.id || c2 === c1.id);
}
Working Example
Use ngValue instead of value on the options. When you patch the form, use the value instead of an object.
<form [formGroup]="myForm" (ngSubmit)="submit(myForm.value)">
<label>Currency: </label>
<select formControlName="currency">
<option [ngValue]="1">USD</option>
<option [ngValue]="2">CAD</option>
<option [ngValue]="3">EUR</option>
</select>
<br>
<button type="submit">Submit</button>
</form>
Example use of patch():
selectCAD() {
this.myForm.controls.currency.patchValue(2);
}
Here's a stackblitz that demonstrates

Default select value for dropdown is not straight forward in Angular 7

I've been working with Angular 7 recently, and finding some strange stuff happening when trying to display a dropdown list, and showing a default value within this list. Here are two separate lists respectively:
sample.component.html
<select [(ngModel)]="organization" id="organization" required>
<option *ngFor="let organization of organizations" [value]="organization.id" [ngValue]="organization.name">{{organization.name}}</option>
</select>
<br>
I find that the above code displays the following in my browser:
Notice how the default value is set in the above, but in the next drop down the default value isn't set:
sample.component.html
<select [(ngModel)]="seniorExperience" id="seniorExperience" required>
<option *ngFor="let seniorExperience of seniorExperiences" [value]="seniorExperience.seniorExperienceId" [ngValue]="seniorExperience.seniorExperienceName">{{seniorExperience.seniorExperienceName}}</option>
</select>
The browser displays the following:
Why is the second dropdown not populated with the a default, whilst following the same syntax? From searching and reading docs I presumed that [ngValue] sets the default value of the dropdown, which seems to work for the first dropdown. Is there a better way to set the default select?
As per Angular 7 implementation:
In HTML:
<select *ngIf="ownerLevels" [value]="selectedOwnerLevel" (change)="onChangeOwnerLevel($event.target.value)" formControlName="ownerLevel" id="ddOwnerLevel">
<option [value]="0" disabled>Select Owner Level</option>
<option *ngFor="let ownerLevel of ownerLevels" [value]="ownerLevel.id">{{ownerLevel.name}}</option>
</select>
In TS:
ownerLevels = [
{ id: 1, name: 'Company' },
{ id: 2, name: 'Department' },
{ id: 3, name: 'Personal Area' }
];
selectedOwnerLevel: number = 0;
onChangeOwnerLevel(ownerLevelId: number) {
this.selectedOwnerLevel = ownerLevelId;
}

DataList in Angular

I have a <datalist> and <select> as follows:
Updated:
Example 1:
<input type="text" list="codes" [(ngModel)]="codeValue" (change)="saveCode(codeValue)">
<datalist id="codes">
<option *ngFor="let c of codeList" [value]="c.code" >{{c.name}}</option>
</datalist>
<select type="text" list="codes" [(ngModel)]="codeValue1" (change)="saveCode(codeValue)">
<option *ngFor="let c of codeList" [value]="c.code" >{{c.name}}</option>
</select>
codeList Array in component.ts
codeList = [
{ code: 'abcdhe568dhjkldn', name: 'item1' },
{ code: 'ksdkcs7238t8cds', name: 'item2' },
{ code: 'kascggibebbi', name: 'item3' }
];
DataList is showing both name (c.name) and value (c.code) in the options and storing whatever is present in value whereas select is showing name (c.name) and storing value(c.code).
Behavior of datalist
Behavior of select
Example 2:
<datalist id="codes">
<option *ngFor = "let i of [1,2,3,4]" [value]="i">{{i-1}}</option>
</datalist>
{{a}}
I want to show the value of i-1 in the suggestion box but bind the variable 'a' with i.
Existing Solution in HTML
From this post Show datalist labels but submit the actual value I see that we can use "data-value" to
acheive the functionality in HTML. How can I achieve the same functionality in Angular.
Please help!
Thanks in advance.
Try Like this....
html File
<input type="text" list="codes" [(ngModel)]="codeValue" (change)="saveCode($event)">
<datalist id="codes">
<option *ngFor="let c of codeList" [value]="c.name" >{{c.name}}</option>
</datalist>
ts File
codeList = [
{ code: 'abcdhe568dhjkldn', name: 'item1' },
{ code: 'ksdkcs7238t8cds', name: 'item2' },
{ code: 'kascggibebbi', name: 'item3' }
];
public saveCode(e): void {
let name = e.target.value;
let list = this.codeList.filter(x => x.name === name)[0];
console.log(list.id);
}
Try it this way.
<option *ngFor = "let i of [1,2,3,4]" (change)="a=i" [value]="i">{{i-1}}</option>
Well, may someone correct me if I'm not telling the truth but you can't bind [value] to 'a', because then every option-element has the same value 'a'.
To achieve what you want you have to build an Array of objects that contain both fields, 'a' and 'i'. Then you can show 'i' and bind your value via ngModel to 'a'.
e.g.
in your component
export class AI {
constructor(
a: number,
i: number
) {}
}
aiList: Array<AI> = [];
ai: AI = new AI(1,0);
aiList.push(ai);
ai = new AI(2,1);
aiList.push(ai);
ai = new AI(3,2);
aiList.push(ai);
ai: = new AI(4,3);
aiList.push(ai);
in your template
<option *ngFor = "let ai of aiList" (change)="a=ai.a" [(ngModel)]="ai.a">{{ai.i}}</option>

Binding select element to object in Angular

I'd like to bind a select element to a list of objects -- which is easy enough:
#Component({
selector: 'myApp',
template:
`<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="#c of countries" value="c.id">{{c.name}}</option>
</select>`
})
export class AppComponent{
countries = [
{id: 1, name: "United States"},
{id: 2, name: "Australia"}
{id: 3, name: "Canada"},
{id: 4, name: "Brazil"},
{id: 5, name: "England"}
];
selectedValue = null;
}
In this case, it appears that selectedValue would be a number -- the id of the selected item.
However, I'd actually like to bind to the country object itself so that selectedValue is the object rather than just the id. I tried changing the value of the option like so:
<option *ngFor="#c of countries" value="c">{{c.name}}</option>
but this does not seem to work. It seems to place an object in my selectedValue -- but not the object that I'm expecting. You can see this in my Plunker example.
I also tried binding to the change event so that I could set the object myself based on the selected id; however, it appears that the change event fires before the bound ngModel is updated -- meaning I don't have access to the newly selected value at that point.
Is there a clean way to bind a select element to an object with Angular 2?
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>
StackBlitz example
NOTE: you can use [ngValue]="c" instead of [ngValue]="c.id" where c is the complete country object.
[value]="..." only supports string values
[ngValue]="..." supports any type
update
If the value is an object, the preselected instance needs to be identical with one of the values.
See also the recently added custom comparison https://github.com/angular/angular/issues/13268
available since 4.0.0-beta.7
<select [compareWith]="compareFn" ...
Take care of if you want to access this within compareFn.
compareFn = this._compareFn.bind(this);
// or
// compareFn = (a, b) => this._compareFn(a, b);
_compareFn(a, b) {
// Handle compare logic (eg check if unique ids are the same)
return a.id === b.id;
}
This could help:
<select [(ngModel)]="selectedValue">
<option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
</select>
You can do this too without the need to use [(ngModel)] in your <select> tag
Declare a variable in your ts file
toStr = JSON.stringify;
and in you template do this
<option *ngFor="let v of values;" [value]="toStr(v)">
{{v}}
</option>
and then use
let value=JSON.parse(event.target.value)
to parse the string back into a valid JavaScript object
It worked for me:
Template HTML:
I added (ngModelChange)="selectChange($event)" to my select.
<div>
<label for="myListOptions">My List Options</label>
<select (ngModelChange)="selectChange($event)" [(ngModel)]=model.myListOptions.id >
<option *ngFor="let oneOption of listOptions" [ngValue]="oneOption.id">{{oneOption.name}}</option>
</select>
</div>
On component.ts:
listOptions = [
{ id: 0, name: "Perfect" },
{ id: 1, name: "Low" },
{ id: 2, name: "Minor" },
{ id: 3, name: "High" },
];
An you need add to component.ts this function:
selectChange( $event) {
//In my case $event come with a id value
this.model.myListOptions = this.listOptions[$event];
}
Note:
I try with [select]="oneOption.id==model.myListOptions.id" and not work.
============= Another ways can be: =========
Template HTML:
I added [compareWith]="compareByOptionId to my select.
<div>
<label for="myListOptions">My List Options</label>
<select [(ngModel)]=model.myListOptions [compareWith]="compareByOptionId">
<option *ngFor="let oneOption of listOptions" [ngValue]="oneOption">{{oneOption.name}}</option>
</select>
</div>
On component.ts:
listOptions = [
{ id: 0, name: "Perfect" },
{ id: 1, name: "Low" },
{ id: 2, name: "Minor" },
{ id: 3, name: "High" },
];
An you need add to component.ts this function:
/* Return true or false if it is the selected */
compareByOptionId(idFist, idSecond) {
return idFist && idSecond && idFist.id == idSecond.id;
}
Just in case someone is looking to do the same using Reactive Forms:
<form [formGroup]="form">
<select formControlName="country">
<option *ngFor="let country of countries" [ngValue]="country">{{country.name}}</option>
</select>
<p>Selected Country: {{country?.name}}</p>
</form>
Check the working example here
In app.component.html:
<select type="number" [(ngModel)]="selectedLevel">
<option *ngFor="let level of levels" [ngValue]="level">{{level.name}}</option>
</select>
And app.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
levelNum:number;
levels:Array<Object> = [
{num: 0, name: "AA"},
{num: 1, name: "BB"}
];
toNumber(){
this.levelNum = +this.levelNum;
console.log(this.levelNum);
}
selectedLevel = this.levels[0];
selectedLevelCustomCompare = {num: 1, name: "BB"}
compareFn(a, b) {
console.log(a, b, a && b && a.num == b.num);
return a && b && a.num == b.num;
}
}
For me its working like this, you can console event.target.value.
<select (change) = "ChangeValue($event)" (ngModel)="opt">
<option *ngFor=" let opt of titleArr" [value]="opt"></option>
</select>
The key is to use a two way binding in the select via [(ngModel)] and use [ngValue] in each option.
You can even have a default null option and it works with Angular 12.
<select name="typeFather" [(ngModel)]="selectedType">
<option [ngValue]="null">Select a type</option>
<option *ngFor="let type of types" [ngValue]="type">{{type.title}}</option>
</select>
That approach is always going to work, however if you have a dynamic list, make sure you load it before the model.
You Can Select the Id using a Function
<option *ngFor="#c of countries" (change)="onchange(c.id)">{{c.name}}</option>
Create another getter for selected item
<form [formGroup]="countryForm">
<select formControlName="country">
<option *ngFor="let c of countries" [value]="c.id">{{c.name}}</option>
</select>
<p>Selected Country: {{selectedCountry?.name}}</p>
</form>
In ts :
get selectedCountry(){
let countryId = this.countryForm.controls.country.value;
let selected = this.countries.find(c=> c.id == countryId);
return selected;
}
Also, if nothing else from given solutions doesn't work, check if you imported "FormsModule" inside of "AppModule", that was a key for me.
You can get selected value also with help of click() by passing the selected value through the function
<md-select placeholder="Select Categorie"
name="Select Categorie" >
<md-option *ngFor="let list of categ" [value]="list.value" (click)="sub_cat(list.category_id)" >
{{ list.category }}
</md-option>
</md-select>
use this way also..
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
<option *ngFor="let c of countries" value="{{c.id}}">{{c.name}}</option>
</select>
Attention Angular 2+ users:
for some reason, [value] does not work on elements. use [ngModel] instead.
<select [ngModel]="selectedCountry">
<option *ngFor="let country of countries" [value]="country">{{country.name}}</option>
</select>
Tested on Angular 11. I need an extra object 'typeSelected'. Pay attention I'm not using [(ngValue)] as other answers do:
<mat-select formControlName="type" [(value)]="typeSelected"
[compareWith]="typeComparation">
<mat-option *ngFor="let myType of allSurveysTypes" [value]="myType">
{{myType.title}}
</mat-option>
</mat-select>
//Declaration.
typeSelected: SurveyType;
...
//Assigning variable 'type' of object 'survey' to 'typeSelected'.
this.typeSelected = survey?.type;
...
//Function to compare SurveyType objects.
typeComparation = ( option, value ) => {
if (option && value) {
return option.id === value.id;
}
}
This code is very simple:
<select class="form-control" id="marasemaat" [(ngModel)]="fullNamePresentor"
[formControl]="stateControl" (change)="onSelect($event.target.value)">
<option *ngFor="let char of programInfo1;let i = index;"
onclick="currentSlide(9,false)"
value={{char.id}}>{{char.title + " "}} ----> {{char.name + " "+ char.family }} ---- > {{(char.time.split('T', 2)[1]).split(':',2)}}</option>
</select>

Input Type Select value from AngularJS $scope?

How show the Value on input type select when loading data from AngularJS $scope?
The ng-model is filled by controller with an ID from contactTypes
index.html
<select data-ng-model="item.mediumTypeId"
data-ng-options="option.name for option in contactTypes track by option.id">
</select>
controller.js
$scope.item.mediumTypeId = 5102;
Option Values after loading index.html
<option value="5101">E-Mail</option>
<option value="5102">Fax</option>
<option value="5103">Phone</option>
The above Code doesn't select the option in the select field after loading index.html
You need to have:
$scope.item.mediumTypeId = '5102';
As angularjs doesn't convert it to a number automatically.
If your controller contains something like this:
$scope.contactTypes = [{name: 'one', age: 30 },{ name: 'two', age: 27 },{ name: 'three', age: 50 }];
your template should look like this
<div ng-controller="Test">
<p>selected item is : {{item.mediumTypeId}}</p>
<select ng-model="item. mediumTypeId">
<option ng-repeat="item in contactTypes" value="{{item.age}}">{{item.name}}</option>
</select>
</div>
I hope this helps