Values not displaying in Angular select box while binding Ngmodel - html

I am a beginner in Angular and when I tried to display object by looping in select box, it not displaying any values. Only showing blank dropdown.
My html page like the following:
<div *ngIf="userPermissionObj">
<select id="permission">
<option *ngFor="let obj of permissionType"
[value]='permissionType.value'
[selected]="userPermissionObj.sPermissionType == obj.value ? true : null">
{{permissionType.viewValue}}
</option>
</select>
</div>
My component ts file contains like the following code,
getUserPermisionsByUsernameSearch()
{
var param:string=this.permissionRequestUser;
this.manageuserService.getUserPermissionApiMethod(param)
.subscribe((data:any)=> {this.userPermissionObj=data;});
}
permissionType = [
{value: 'R', viewValue: 'Read'},
{value: 'W', viewValue: 'Write'}
];
Where have I wrongly implemented my html page?

You should replace [value]='permissionType.value' by [value]='obj.value' and {{permissionType.viewValue}} by {{obj.viewValue}} because permissionType is the array you are looping with.
So you're HTML should look like this
<div *ngIf="userPermissionObj">
<select id="permission">
<option *ngFor="let obj of permissionType"
[value]='obj.value'
[selected]="userPermissionObj.sPermissionType == obj.value ? true : null">
{{obj.viewValue}}
</option>
</select>
</div>

For a correct data binding you have to add an ngModel to the select and remove the selected attribute of the option.
<div *ngIf="userPermissionObj">
<select id="permission" [(ngModel)]="userPermissionObj.permissionType">
<option *ngFor="let permission of permissionType"
[value]="permission.value">
{{permission.viewValue}}
</option>
</select>
</div>
in you ts
getUserPermisionsByUsernameSearch(): void
{
const param:string=this.permissionRequestUser;
this.manageuserService.getUserPermissionApiMethod(param)
.subscribe((data:any)=> {
this.userPermissionObj = data;
});
}
permissionType = [
{value: 'R', viewValue: 'Read'},
{value: 'W', viewValue: 'Write'}
];

Instead of {{permissionType.viewValue}}, use{{obj.viewValue}}.
The iteration *ngFor="let obj of permissionType" where you chose obj as a variable. So you will have to use the same variable for the value interpolation.

Related

Can't figure out a way to add two values from a select element in react

Scenario: I have a react component that allows users to select through different shipping rates. Once a user selects one I want the onChange to get the ID and the amount and I can only figure out how to get just the ID. The select element iterates through an array of rates that is structured like this:
rates = [ {id: 'r8f8hd8', amount: 45}, ...]
Here is the select element:
<select onChange={(e) => console.log(e.target.value)} className='w-8/12 h-14 rounded p-2'>
<option disabled selected hidden>
Pick a shipping rate
</option>
{rates.map((rate, index) => (
<option value={{ id: rate.rateId, amount: rate.amount }} key={index}>
{rate.service} {''}(${rate.amount})
</option>
))}
</select>
I tried setting the option value to an object with the rateId and amount but it just gives me a blank [Object object]
This should fix the issue. A word of advice I wouldn't set the key to just the index. Instead you should use the id that you assigned to the object.
The issue was you we're storing an object as the value. This lead to an issue because value automatically stores a string so your object is converted into a string hence [Object Object]. Mapping already sets its own pre defined object {value:someVal,key:someID}.
Taking your current case into account I believe this is a cleaner way to achieve what you wanted. I've added working code below. Also the extra item in rates was just for testing.
Feel free to comment any questions you have and i'll do my best to answer them.
let rates = [ {id: 'r8f8hd8', amount: 45},{id: 'r8f8hd', amount: 450}]
return (
<select onChange={(e) => console.log(e.target.value)} className='w-8/12 h-14 rounded p-2'>
<option disabled selected hidden>
Pick a shipping rate
</option>
{rates.map((rate) => (
<option value={rate.amount } key={rate.id}>
{rate.service} {''}(${rate.amount})
</option>
))}
</select>
)
Just incase your just dead set on storing multiple values here's a solution to that as well but I would go as far as saying this is just bad code but it does what you wanted. Since map has its own object as I mentioned we can mutate it and give it more characteristics hence id and trueVal that I added. We can use the index and store that as our value and instead of accessing our data through e.target.value we can instead utilize the e.target.options and simply cross reference the index value we stored to make sure we are always accessing the correct position in the array. However please take note of the +1 this is to take the first position into account which is held by the, "Pick a shipping rate".
let rates = [ {id: 'r8f8hd8', amount: 45},{id: 'r8f8hd', amount: 450}]
return (
<select onChange={(e) => console.log(e.target.options[e.target.value])} className='w-8/12 h-14 rounded p-2'>
<option disabled selected hidden>
Pick a shipping rate
</option>
{rates.map((rate, index) => (
<option value={index+1} trueVal={rate.amount} id={rate.id} key={index}>
{rate.service} {''}(${rate.amount})
</option>
))}
</select>
)
}
In html value prop is a string, so value={{ id: rate.rateId, amount: rate.amount }} is converted to string, that's why you are getting [Object object] .
Solution : change your component like this :
.....
const [option, setOption] = React.useState({});
const handlechange = (e)=>{
for (let i = 0; i < rates.length; i++) {
if (e.target.value === rates[i].id) {
setOption({ id: rates[i].id, amount: rates[i].amount });
}
}
}
return (
<select onChange={handlechange} className="w-8/12 h-14 rounded p-2">
<option disabled selected hidden>
Pick a shipping rate
</option>
{rates.map((rate, index) => (
<option value={rate.id} key={index}>
{rate.service} {""}(${rate.amount})
</option>
))}
</select>
);
Now your id and amount of selected option will be stored in option state
this is a demo in codesandbox

Select control doesn't show when published in Azure

I have got a weird situcation here. I have a select control on a web page with angular. It shows correctly in local environment.
However, when I published it to Azure, The select control does not show correctly.
This is local showing.
This is on Azure site showing.
This is inspect of select control on local site. Which looks good.
This is inspect of select control on Azure site. As it can be seen that, the select control is empty.
Here is the html for select control, I create a component for customize showing.
<div class="dynamic-field row" [formGroup]="group">
<label class="col-form-label" [ngClass]="'col-'+config.labelSize" *ngIf="config.labelSize!==0">{{ config.label }}</label>
<div [ngClass]="'col-'+ (12 - (config.labelSize||0))">
<div class="input-group input-group-sm">
<div class="input-group-prepend" *ngIf="config.prepend">
<span class="input-group-text" *ngIf="!config.prependConfig" [innerHTML]="config.prepend"></span>
<span class="input-group-text cursor-pointer" *ngIf="config.prependConfig" cspsDynamicFormModalLink [innerHTML]="config.prepend"
[config]="config.prependConfig"></span>
</div>
<select [formControlName]="config.name" class="form-control">
<option [ngValue]="undefined" *ngIf="config.placeholder">{{ config.placeholder }}</option>
<option [ngValue]="option.key" *ngFor="let option of options">
{{ option.value }}
</option>
</select>
<div class="input-group-append" *ngIf="config.append">
<span class="input-group-text" *ngIf="!config.appendConfig" [innerHTML]="config.append"></span>
<span class="input-group-text cursor-pointer" *ngIf="config.appendConfig" cspsDynamicFormModalLink [innerHTML]="config.append"
[config]="config.appendConfig"></span>
</div>
</div>
</div>
</div>
Here is the ts file:
#Component({
selector: 'form-select',
templateUrl: 'form-select.component.html',
styleUrls: ['form-select.component.css']
})
export class FormSelectComponent implements Field, OnInit {
config: FieldConfig;
group: FormGroup;
options: { key: any, value: string }[];
ngOnInit() {
const sorter = {
asc: (a: { value: string }, b: { value: string }) => { return a.value === b.value ? 0 : (a.value > b.value ? 1 : -1) },
desc: (a: { value: string }, b: { value: string }) => { return a.value === b.value ? 0 : (a.value < b.value ? 1 : -1) },
none: undefined
}
this.config.sortOptions = this.config.sortOptions || 'none';
if (this.config.options)
this.options = this.config.options.sort(sorter[this.config.sortOptions]);
else
this.options = [];
}
}
Could anyone give me some suggestions? Or tell me what's going on?
Thanks

Angular: Getting a second value of a json file based on a select input

I have this json:
[
{"country" : "Afghanistan","city" : "Kabul"},
{"country" : "Albania","city" : "Tirana"},
{"country" : "Algeria","city" : "Alger"},
And I want to have a select that when choosing a country, I get the city displayed
My service:
getCountries(name?: string, city?: string, expectancy?: string, polulation?: string, government?: string) {
let cities = this.http.get('assets/capitals.json'); -> this is the one called
let language = this.http.get('assets/languages.json');
return forkJoin([cities, language]);
}
Component:
ngOnInit() {
this.weatherService.getCountries()
.subscribe(dataList => {
this.cities = dataList[0]
console.log(this.capitals)
this.population = dataList[1]
console.log(this.cities, this.population)
})
}
onChange(deviceValue) {
console.log(deviceValue)
}
View:
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<select (change)="onChange($event.target.value)" class="form-control">
<option style="color:black" *ngFor="let c of cities" value="{{c.country}}">{{c.country}}</option>
</select>
</div>
</div>
</div>
It sounds very simple but something is missing. If it were an API I would pick up the select value and make another call with that value on url, but like this, how can I achieve it?
Your function is logging the value of the "select" component which in your case happens to be the country. If you want to display the country but use the city as the value, you simply change the following in the HTML:
<select (change)="onChange($event.target.value)" class="form-control">
<option style="color:black" *ngFor="let c of cities" value="{{c.city}}">{{c.country}}</option>
</select>
Using the above, the country will be displayed but your "onChange" function will log the city value. If you wish to do something else with the city value, you can do so in your onChange function.

Display label displayed in options as the title of select

How to show option.Brand.Name as the title of the select field without using java script and changing the ng-model?
<select ng-model="detail.BrandId" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
AngularJS and select-options
Try using ng-options AngularJS ngOptions directive within select element itself. Then you don't need to add each option element yourself using ng-repeat.
Clarification
The title-attribute belongs to the select-element and will show if you hover over the select. You would like the title to reveal the current selected option? Did I understand you correctly?
How to show option.Brand.Name as the title of the select field
Curious, where this detail.ProductId comes from? Is the brand preselected by product-id (see your code)?
ng-selected="option.Id === detail.ProductId"
Solution space
Your requirements/restrictions are:
without using JavaScript (maybe because you can't change the sources)
without changing the ng-model (because you need there only the BrandId for some database-reasons)
So since the title of the select-element has no access to the options inside, the only way to set it is depending on the current selection, i.e. your detail.BrandId. So the title can only set dynamically (depending on the current selection) by using standard-angularJS means, as:
{{ expression }} expressions
{{ expression | filter }} array-filter
Expected behavior
The only scope-variable changed by selecting is specified within select's ng-model as detail.BrandId. This will be set when user selects an option to its property BrandId. When user selects between options they will be visible with ther BrandName as label. After selection this BrandName (label of the option) should be shown as title of the entire select element.
So we need to get from detail.BrandId (selected ng-model) to related options BrandName (as this should show as title).
Possible Solution
Only way is to use standard angular expressions/filters/array-indexing to get the whole option by the selected detail.BrandId (ng-model)
Then we can lookup the option.BrandName by this equation after selected detail.BrandId === option.BrandId
var app = angular.module('app', []);
app.controller('mainCtrl', function($scope){
$scope.products = [
{Id: 0, name: 'Watson', brandId: 1, brandName:"IBM"},
{Id: 1, name: 'DB2', brandId: 1, brandName:"IBM"},
{Id: 2, name: 'Windows', brandId: 2, brandName: "Microsoft"},
{Id: 3, name: 'Office', brandId: 2, brandName: "Microsoft"}
];
$scope.detail = { ProductId: 3, BrandId: null };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<!DOCTYPE html>
<html>
<body data-ng-app="app" data-ng-controller="mainCtrl">
<table border="1">
<tr>
<th>Product Id</th><th>Product Name</th><th>Choose Brand</th><th>Brand Id</th>
</tr>
<tr>
<td>{{detail.ProductId}}</td>
<td>{{ (products | filter: {Id: detail.ProductId})[0].name }}</td>
<td>
<select class="form-control"
ng-model="detail.BrandId"
ng-init="detail.BrandId = (products | filter: {Id: detail.ProductId})[0].brandId"
ng-options="o.brandId as ('['+ o.Id +'] '+ o.name +' : '+ o.brandName +' ('+ o.brandId +')') for o in products"
title="{{ (products | filter: {brandId: detail.BrandId})[0].brandName}}"
>
<!-- default option when not preset by detail.ProductId-->
<option value="">-- please choose brand --</option>
</select>
</td>
<td>{{detail.BrandId}}</td>
</tr>
</table>
<hr/>
<p>Product is predefined. So the brand is pre-selected by product. BUT: after brand is selected, the product-details do NOT change!</p>
Selected <strong>detail</strong>:
<pre ng-model="selected">{{detail | json}}</pre>
</body>
</html>
See also
For using ng-options, see also plunkr example.
You can register the selected option object in the ng-repeat parent scope by using as alias-expression provided by ng-repeat.
In your case you just need to do something like that:
<select ng-model="detail.BrandId"
title="{{options | selectedProductFilter : detail.ProductId}}"
class="form-control"
disabled>
<option ng-repeat="option in mainCtrl.products as options"
ng-selected="option.Id === detail.ProductId"
ng-value="option.BrandId">
{{option.Brand.Name}}
</option>
</select>
The options object will be available in your controller closure and you can display the title by using a custom filter.
angular.module("app").filter('selectedProductFilter',
function () {
return function (input, id) {
if (!input) return "";
let occurence = input.filter(function (x) {
return x.Id == id;
});
return occurence.length > 0 ? occurence[0].Brand.Name: "";
}
}
);
you need to do ng-change event in your select and call function in it that change the value of label text to the select value name. something like below
In Html
ng-change="changedValue(detail.BrandId)"
In JS
$scope.changedValue = function(item) {
//change label name here
}
fill ng-model by "option" not "option.BrandId"
then you can set title like this :
mainCtrl.products['ng-model-name'].Brand.Name
Here's how you could achive this:
(function () {
"use strict";
const app = angular.module("app", []);
app.controller("app.AppCtrl", $scope => {
$scope.selectedOption = null;
$scope.optionList = [{_id: 1, label: 'Option 1'}, {_id: 2, label: 'Option 2'}];
});
})();
body {
margin: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="app.AppCtrl">
<select title="{{selectedOption.label}}" class="form-control" ng-model="selectedOption">
<option ng-repeat="option in optionList" ng-value="option"> {{option.label}}</option>
</select>
</div>
Try using ng-init,
add ng-init to your select tag and put your object index value you want to be selected by default.
e.g.
Your code
<select ng-model="detail.BrandId" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
adding following code (Suppose I want index 0 by index):
ng-init="detail.BrandId = option[0].Brand.Name"
It will look like this :
<select ng-model="detail.BrandId" ng-init="detail.BrandId = option[0].Brand.Name" title="" class="form-control" disabled>
<option ng-repeat="option in mainCtrl.products" ng-selected="option.Id === detail.ProductId" ng-value="option.BrandId">{{option.Brand.Name}}</option>
</select>
or Check these thread's
how to use ng-option to set default value of select element
How to set default value in ng-options

How to change select tags value when element is deleted from array?

I have select tag which takes values from array like this
<select class="groupForArchive" ng-model="selected.country">
<option ng-selected= "{{country == selected.country}}" ng-repeat="country in countrynList" value={{country}}> {{ country.name }} </option>
</select>
when I am deleting element from array(countryList) I am setting new value to this tag like this $scope.selected.country = newValue, but in select box I am getting free space like in this pictures.
before delete country from list
after delete country from list
and when I am taking select tag's ng-model I am getting correct object but I can not see it in my select box and I don't know which item is selected.
P.S newValue is array's another item(item from countrynList)
How can I fix it ?
Update AngularJS library to latest version and make changes, presented below:
angular.module('app', []).controller('ctrl', function($scope){
$scope.countrynList = [
{name:'USA'}, {name:'Spain'}, {name:'France'}, {name:'Germany'}
]
$scope.selected = {country: $scope.countrynList[0]};
$scope.Delete = function(){
var index = $scope.countrynList.indexOf($scope.selected.country);
$scope.countrynList.splice(index, 1);
$scope.selected.country = $scope.countrynList[0];
}
})
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl'>
<select class="groupForArchive" ng-model="selected.country">
<option ng-repeat="country in countrynList" ng-value='country'>
{{country.name}}
</option>
</select>
{{selected.country}}
<br>
<input type='button' ng-click='Delete()' value='Delete First'/>
</div>