Ng-options selecting value as a int instead of a string - javascript

I have an array of objects
usage: [{label: 'Main', value: '30' },{ label: 'Second', value: '27' },{ label: 'Third', value: '50' }];
This is how I use the ng-options
<select class="Input" ng-model="myCtrl.data.usages" ng-options="usage.value as usage.label for usage in myCtrl.data.usages">
It seems to work as it selects the right value.. However it selects as a string. Is there a way to make it select / parse as integer? So instead of '27', it will save as 27

You could make a filter for this. This will allow you to parse and manipulate the value however you wish. Observe the following example...
app.filter('num', function() {
return function(input) {
return parseInt(input, 10);
};
});
<select
ng-options="(usage.value | num) as usage.label for usage in myCtrl.data.usages">
</select>
JSFiddle Link - demo

Related

SELECT --> OPTION, using value vs ngValue

I just recently figured out that there is an alternative for value property on OPTION part of the SELECT, namely ngValue. The docs really lack documentation about this (all I could find: https://angular.io/docs/ts/latest/api/forms/index/NgSelectOption-directive.html). Anyway, the idea is that when you use an object for the ngModel, you can use ngValue and it works well. Otherwise, only e.g. ID is updated. If we're having just an array of strings, value is sufficient. Here are the examples:
{{myModel | json}}
<select [(ngModel)]="myModel">
<option *ngFor="let i of items" [ngValue]="i">{{i.value}}</option>
</select>
<br /><br />
{{mySimpleModel}}
<select [(ngModel)]="mySimpleModel">
<option *ngFor="let i of simpleItems" [value]="i">{{i}}</option>
</select>
While this works as expected, there's a distinctive differences between the two: if using ngValue, the predefined value is not selected in the drop down, whereas for the primitive types, the value is selected on loading. E.g.:
items: any[] = [{id: 1, value: 'item1'}, {id: 2, value: 'item2'}, {id: 3, value: 'item3'}];
myModel: any = {id: this.items[1].id , value: this.items[1].value};
simpleItems: string[] = ['item1', 'item2', 'item3'];
mySimpleModel: string = this.simpleItems[1];
See example here: https://plnkr.co/edit/JBrtmx7QkPZztBjaqYkS?p=preview
So, why does Angular set the default value for strings, but not for objects? And what is the most elegant workaround?
You don't need a "workaround" for that. When you do this
myModel = {id: this.items[1].id , value: this.items[1].value};
you are creating a new object which has the same values as this.items[1] but it is not the same object, it's a new one.
const items = [{id: 1, value: 'item1'}, {id: 2, value: 'item2'}, {id: 3, value: 'item3'}]
const myModel = {id: 2, value: 'item2'};
console.log(items[1] === myModel);
that is the reason why your select can't find that value in the <option> list.
In order to fix that, you have to use a proper reference
items = [
{id: 1, value: 'item1'},
{id: 2, value: 'item2'},
{id: 3, value: 'item3'}
];
myModel = this.items[1]
plunkr
In order to obtain default selected option using [ngValue] you can use [compareWith].
Just change in the method compareObj the correct atribute for the Object your comparing.
<select [compareWith]="compareObj" [(ngModel)]="selectedObject">
<option *ngFor="let object of objects" [ngValue]="object">
{{object.name}}
</option>
</select>
compareObj(o1: Object, o2: Object) {
return o1.id === o2.id;
}

How to determine binding type for items in a sap.m.Select?

When using a sap.m.Input, I can configure the element like in the example below, in order to set the type of the item that is binded to the Input:
<mvc:View>
<Input value="{
path:'/company/revenue',
type: 'sap.ui.model.type.Float'
}"/>
</mvc:View>
this way, when I retrieve the property inside '/company/revenue', its type will always be a JavaScript number. However, is it possible to apply a similar "typing" to a sap.m.Select? The property "selectedKey" inside a sap.m.Select always returns a JavaScript String, but I would like to type it to a number like I did with the sap.m.Input above. How can I do it? Thanks in advance!
Yes, you can do that. It's just a normal property binding.
But beware that the keys of your items inside the Select control have to be compatible with the Float type. The sap.ui.model.type.Float without any formatOptions generates locale dependant strings. So in germany f.e. you get a , as decimal separator and in the US it would be ..
A good idea would be to use a aggregation binding to create the items and configure the keys of the items with the same type as the selectedKey property of your select. See example on JSbin.
<Select
selectedKey="{path:'/selectedKey',type: 'sap.ui.model.type.Float'}"
items="{/items}">
<c:ListItem
key="{path: 'key', type: 'sap.ui.model.type.Float'}"
text="{text}"/>
</Select>
onInit:function(){
var data = {
selectedKey:3,
items: [
{ key: -1, text: "Item 1" },
{ key: 1.234, text: "Item 2" },
{ key: 3, text: "Item 3" },
{ key: 1234, text: "Item 4" }
]
};
var model = new sap.ui.model.json.JSONModel(data);
this.getView().setModel(model);
}

How to convert id as order number in ng-options group by..?

This is my code
Fiddle Link
HTML
<div ng-app ng-controller="MyCtrl">
<input type="text" ng-model = "data.name" ><br>
<input type="text" ng-model = "data.value" ><br>
<input type="text" ng-model = "data.id" ><br>
<input type="button" value="ADD" ng-click = "addIntoArr(data.name,
data.value, data.id)" ng-disabled= !data.name>
<select ng-model="selectItem" ng-options="currOption as 'order' +
(data.indexOf(currOption)+1) group by currOption.name for currOption
in data"></select>
Data : {{selectItem.name}}
</div>
Here is my Js code
function MyCtrl($scope) {
$scope.data = [{
name: "AM",
value: "11",
id: "2"
}, {
name: "PM",
value: "12",
id: "3"
}, {
name: "PM",
value: "12",
id: "23"
}, {
name: "PM",
value: "12",
id: "33"
}, {
name: "AMT",
value: "13",
id: "33"
}, {
name: "WAT",
value: "14",
id: "21"
}];
$scope.addIntoArr = function (name, value, id) {
$scope.data.push({
name: name,
value: value,
id: id
});
}
$scope.selectItem = $scope.data[0];
}
Here is my array I was using label AM, PM, AWT, WAT. and each has a order (Please check fiddle link). I want each label order show with number like order1 in AM, order1, order2, order3 in PM and so on. and if I add new entry in array then recently added entry should be shown in drop down with order number and Related label shown in Data.
You cannot use $index inside ng-options. However you can get the current index by using indexOf on the data item passing the current option.
<select
ng-model="selectItem"
ng-options="currOption as 'order' + (data.indexOf(currOption)+1) group by currOption.name for currOption in data"></select>
Demo http://jsfiddle.net/6cf3h54x/3/
I'd suggest you include some external library like lodash and format your data into more convenient structure. Then, instead of banging your head against the wall with ng-options, you could use ng-repeat.
Consider the following:
// group existing data by object's name using lodash _.groupBy
$scope.groupedData = _.groupBy($scope.data, 'name');
This gives your following data structure for groupedData, so there's key and value where key is e.g. AM and value is array of objects all having same name.
Then you could have following template for your select.
<select ng-model="selectItem">
<optgroup ng-repeat="(key, items) in groupedData" label="{{ key }}">
<option ng-repeat="item in items"
value="{{ item }}"
ng-bind="'order' + (items.indexOf(item) + 1)"></option>
</optgroup>
</select>
Which gives you what you are after, no?
You can't use $index with ng-options. Make use of indexOf instead. You can do something like this:
<select ng-model="selectItem" ng-options="currOption.id as 'order'+data.indexOf(currOption) group by currOption.name for currOption in data"></select>

Angularjs: update select options

I have two select menus . One for country selection and other for state. I need to update states based country selected. I am able to log states but not able to list them in select menu.Please help.
Angular:
angular.module('demoApp', []).controller('DemoController', function($scope) {
$scope.countries = [
{ label: 'Please select', value: 0 },
{ label: 'India', value: 1 },
{ label: 'US', value: 2 }
];
$scope.data = [{'1':[{ label: 'Delhi', value: 0 },{ label: 'Mumbai', value: 1 },{ label: 'Chennai', value: 2 }]},
{'2':[{ label: 'Alabama', value: 3 },{ label: 'Alaska', value: 4 },{ label: 'Arizona', value: 5 }]}];
$scope.vm = {states: []};
$scope.updateStates = function(countryCode){
$scope.vm.states = $scope.data[countryCode-1];
console.log($scope.vm.states);
};
$scope.correctlySelected = $scope.countries[0];
});
HTML:
<body ng-app="demoApp">
<div ng-controller="DemoController">
<select ng-model="correctlySelected" ng-change="updateStates(correctlySelected.value)" ng-options="opt as opt.label for opt in countries">
</select>
<select ng-options="opt as opt.label for opt in vm.states">
</select>
</div>
</body>
JS Bin:
http://jsbin.com/pafosewedo/1/edit?html,js,console,output
You need to add ng-model to your states <select> - this is required when you are using ng-options
You also have an inconvenient model for the states data. Each element of the data array that corresponds to the country's states is an object with a changing key whose value is an array of states. You could make it work, but it's better to change it to something more reasonable:
$scope.data = {
1: [{ label: 'Delhi', value: 0 }, {...}, ],
2: [{...}, {...}, ] // same for US
}
Then it would work with how you specified your ng-options for states, and you wouldn't have to deal with indices:
$scope.updateStates = function(countryCode){
$scope.vm.states = $scope.data[countryCode]; // access by property
};
I think, that you should use some filter like that if you don't want to change your model:
.filter('stateFilter', function() {
return function(states, countryID) {
var filtered = [];
angular.forEach(states, function(state){
if(state.value === countryID)
filtered.push(state);
});
return filtered;
};
});
to filter out all values that have value equal to selected country.value in first select control.
To use that filter you need to modify your ng-repeat directive value in state select control:
ng-options="state as state.label for data | stateFilter:correctlySelected"
I came up with the following solution, view my JSBin
This solutions works by setting the countryCode in the scope when we are updatingStates.
$scope.updateStates = function(countryCode){
$scope.countryCode = countryCode;
$scope.vm.states = $scope.data[countryCode-1];
console.log($scope.vm.states[countryCode]);
};
This change is then reflected in the view.
<select>
<option ng-repeat='i in vm.states[countryCode]'> {{i.label}}
</option>
</select>

set option value in dropdown

I am attempting to set an option in a dropdown/select. I have done this before, but for some reason I am getting an error and I am not sure why.
Code
var _loc = {
ALL_BUYS: [{ Text: "All Buys", Value: "AAA"}],
NETWORK_BREAK: [{ Text: "Network Break", Value: "NTN"}],
SYNDICATED_BREAK: [{ Text: "Syndicated Break", Value: "STA"}],
LOCAL_BREAK: [{ Text: "Local Break", Value: "LTA"}],
NATIONAL_LOCAL: [{ Text: "National/Local", Value: "LTN"}],
LOCAL_LOCAL: [{ Text: "Local/Local", Value: "LTL"}]//,
};
lstOptions = $("<select></select>");
$.each(_loc, function (i, item)
{
$("<option></option>")
.appendTo(lstOptions)
.html(item.Text)
.val(item.Value) // receive error: Object has no method 'val'
});
You're not grabbing the values from the object correctly.
The format is like so:
{key1:[{0, 1}], key2:[{0, 1}], key3:[{0, 1}]}
When you use $.each, it selects each one in this state:
[{0, 1}]
On the first iteration, it would select the value associated with key1, on the second, key2, etc.
Since you have arrays nested in each key's value, you need to specify that it locate the first array in the matched value:
var _loc = {
ALL_BUYS: [{ Text: "All Buys", Value: "AAA"}],
NETWORK_BREAK: [{ Text: "Network Break", Value: "NTN"}],
SYNDICATED_BREAK: [{ Text: "Syndicated Break", Value: "STA"}],
LOCAL_BREAK: [{ Text: "Local Break", Value: "LTA"}],
NATIONAL_LOCAL: [{ Text: "National/Local", Value: "LTN"}],
LOCAL_LOCAL: [{ Text: "Local/Local", Value: "LTL"}]
};
lstOptions = $("select");
$.each(_loc, function(i, item){
$("<option></option>")
.appendTo(lstOptions)
.html(item[0].Text)
.attr("value", item[0].Value);
});​
Demo.
Note the item[0]. What this does is select the array with the index 0 in the value that it grabbed. Since there is only one, that single array's index is 0, so it's selecting that specific one. Then you find and set its text and value.
Also note that I changed val() to attr(), because option elements don't support val() (you could, however, use it on a select element to set the option whose value is equal to the one specified in this function to make it selected).
TIP: You could also get rid of the literal array indicators around each nested object and use the original method. Demo.
<option> elements do not support val(). I think you want to use attr()
.attr("value", item.Value)
.val() is used to get the value of form elements. It is not a short-cut to setting the value attribute of an element. To do this, you can use:
.attr("value", item.Value)
Figured it out. I want my items in the loop to be in the following format
Item: "All Buys"
Value: "AAA"
Instead they were in this format
[0]Option
Item: "All Buys"
Value: "AAA"
If I change my loop to this it works
$.each(_loc, function (i, item)
{
$("<option></option>")
.appendTo(lstOptions)
.html(item[0].Text)
.val(item[0].Value);
});

Categories

Resources