SELECT --> OPTION, using value vs ngValue - javascript

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;
}

Related

How to store & retrieve an object as a value in option of select element?

How to store & retrieve an object as a value for option of select element?
<select>
<option value = "{}" selected>lorem</option>
</select>
This isn't a great pattern to use. You should have the select use some UUID (or a unique ID field from you object) as the value for your select, and use the name or description to display to the user.
Then on form submission, you can use Array.find() to get the object that was selected.
agree with KiaiFighter. create an array of objects. and populate/create your options from it. then use the filter function to retrieve the selected object. run the snippet below for an example
const myarray = [
{value: 'one', text: 'one', otherstuff: 'A'},
{value: 'two', text: 'two', otherstuff: 'B'},
{value: 'three', text: 'three', otherstuff: 'C'},
{value: 'four', text: 'four', otherstuff: 'D'},
]
const options = myarray.map(x => `<option value="${x.value}">${x.text}</option>`);
$('#myselect').append(options);
// find elements
$('#mybutton').click(()=> console.log(myarray.filter(x => x.value == $('#myselect').val())[0]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id = "myselect">
</select>
<button id="mybutton">
submit
</button>
To store object in option value:
var objVar = btoa(unescape(encodeURIComponent(JSON.stringify({}))));
$('#optionId').append(`<option value = "`+objVar+`">OPTION DATA</option>`);
To retrieve object from selected option value:
var retrieveData = JSON.parse(atob($('#optionId').val()))

ng-options model bind based on property

Hi I am quite new to angular programming and I had a question on angular's ng-options.
I have an object structure like
TestObj: { name: 'Name1', subNames: ['Subname1'] }
TestArr:
[{ name: 'Name1', subNames: ['Subname1'] },
{ name: 'Name2', subNames: ['Subname1'] },
{ name: 'Name3', subNames: ['Subname1'] }]
And I am trying to use ng-options to bind one of the TestArr objects to TestObj.
<select class="touchpoint-settings-create-channel-box ng-model="TestObj" ng-options="curTest.name for curTest in TestArr"></select>
However, is there any way to make TestObj bind to the object in TestArr that has the same 'name' property?
This jsfiddle is a good example of what I mean. http://jsfiddle.net/KN9xx/840/
When it first starts up, selectedPerson is set to an object similar to the first item in the array, but ng-options does not realize it is the same object.
Thank you
I would not recommend following the example in that jsfiddle. Essentially, you do not want TestObj AND TestArr. If TestObj is not just a reference to TestArr, they are not going to be the same object and you're duplicating data because Angular and JavaScript do not recognize that the two objects have the same keys and values when they are separate objects.
You should follow the example in this SO post: How to have a default option in Angular.js select box
Rather than using TestObj like you are, use ng-init to set the default value.
var TestArr =
[{ name: 'Name1', subNames: ['Subname1'] },
{ name: 'Name2', subNames: ['Subname1'] },
{ name: 'Name3', subNames: ['Subname1'] }];
<select
class="touchpoint-settings-create-channel-box
ng-init="TestObj = options[0]"
ng-model="TestObj"
ng-options="option.name for option in TestArr">
</select>
To illustrate my point on objects:
var obj1 = { name: 'Me' };
var obj2 = { name: 'Me' };
While obj1 and obj2 look exactly the same, the variables are just references to the underlying object, not the values, and the JS interpreter doesn't know that I intend both of those objects to be the same. However, if you strings or numbers, it works like you expect.
var me = 'Me';
var stillMe = 'Me';
console.log(obj1 === obj2); // prints false
console.log(me === stillMe); // prints true

How to translate ids to objects in ng-option angular?

I have array of ids and I need to use this array as source of my ng-option directive inside of select. I certainly could find objects with corresponding id in my collection and create an array of objects to use it instead of array of ids but I wonder is there a way of doing it dynamicaly somehow? Like setting a function as source of ng-option?
You can do it with the help of filtering by id inside ngOptions directive expression:
angular.module('demo', []).controller('MainCtrl', function($scope) {
$scope.ids = [1, 4];
$scope.objects = [
{id: 1, name: 'One'},
{id: 2, name: 'Two'},
{id: 4, name: 'Four'}
];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<div ng-app="demo" ng-controller="MainCtrl">
<pre>{{objects}}</pre>
<pre>{{ids}}</pre>
<select ng-model="model"
ng-options="id as (objects | filter:{id: id})[0].name for id in ids">
</select>
{{model}}
</div>

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

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

How to set a value in a drop-down list

I'm facing a problem with setting a value in a drop-down list. The following is the code for my drop-down:
<select class="price-dropdown" ng-model="createCampaign.currency" ng-options="obj.id as obj.symbol for obj in config.currencies"></select>
Here is the object:
[Object, Object]
0: Object
id: "GBP"
name: "GBP"
symbol: "GBP"
__proto__: Object
1: Object
id: "dollar"
name: "Dollar"
symbol: "$"
__proto__: Object
length: 2
__proto__: Array[0]
It's setting 0, 1, 2 as the value instead of id.
I've looked at other questions but haven't been able to make any of the solutions work.
What am I doing wrong?
Its setting the object Ordinal it seems. can you debug and edit in {obj.id} inside ng-options="obj.id as obj.symbol for obj in config.currencies"> to get it right.
I have created a Fiddle for your problem. Over here it is having id as value.
Code Snippet:
<div ng-app="myapp">
<fieldset ng-controller="FirstCtrl">
<select
ng-options="p.name as p.name for p in symbol"
ng-model="selectedPerson"></select>
{{ selectedPerson }}
</fieldset>
</div>
I Think a dropdown list must have a unique identifier among the list.. to identify the correct selection..look in this sample fiddle link it may help you..
<select class="span2" name="SelectedState" ng-model="selectedState" ng-options="state.id as state.name for state in states">
</select>
Controller code:
$scope.states = [{
id: 1, name: 'France'
}, {
id: 2, name: 'UK'
}, {
id: 3, name: 'Germany'
}];
$scope.selectedState = $scope.states[2];
This code will help to solve your problem please check it once
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
<select name="value">
<option ng-repeat="color in colors" value="{{color.name}}">
{{color.name}}
</option>
</select>
It's not bug, it's a feature. angularjs handles ngOptions and ngModel internally, this way it allows you to use any type of object as value in option rather than only strings. This link should help you :) Watch this tutorial this is shortcut for your problem.

Categories

Resources