get select value from a drop with angulars reads error - javascript

I'm trying to get the selected value from a drop down list with angularjs. When I select the value I get this error angular.min.js:108 TypeError: Cannot read property 'ftype' of undefined
HTML
<select name="select" ng-model="queryBy" ng-change="get_search_value(item)">
<option ng-repeat="item in filter" value="{{item.ftype}}">{{item.ftype}}</option>
</select>
JS
$scope.search_type='';
$scope.filter = [
{ id: 1, ftype: "Complaint Type"},
{ id: 2, ftype: "Region" },
{ id: 3, ftype: "District"},
];
$scope.get_search_value=function(item){
$scope.search_type=item.ftype;
alert(item.ftype)
}

My guess is item is invisible on the level of <select>. Whatever is in the <option>(so, the 'item') should be saved in the ng-model value, which is queryBy. Why are you passing item to the get_search_value? Try acessing the queryBy in the get_search_value function instead

I think you've misunderstood AngularJS... It does all of this for you. You don't need to update a separate value and you don't need a change event to do this for you.
Here is what I think you're trying to achieve:
HTML
<select name="select" ng-model="queryBy">
<option ng-repeat="item in filter" value="{{item.ftype}}">{{item.ftype}}</option>
</select>
JavaScript
$scope.filter = [
{ id: 1, ftype: "Complaint Type"},
{ id: 2, ftype: "Region" },
{ id: 3, ftype: "District"}
];
// you can access the selected value by using $scope.queryBy
That's right, just using $scope.queryBy (or just queryBy in your HTML) will give you the value of the selected option. As tymeJV mentioned, you can also use ngOptions instead of ngRepeat for your options. I'd also recommend looking into using ngBind instead of curly braces where you can, it will avoid the expression itself flashing before being evaluated.

You should be using ngOptions - your item is inaccessible the way you currently have it. Here's a quick refactor that should work:

Related

Change ng-model before submit

I have simple model that submits a form that are all from a select I am using an ng-repeat like so:
'Ctrl'
isdom.scheduleOptions = ['Pass', 'N/A'];
'html'
<select ng-model="isdom.isdomForm.isDom101">
<option ng-repeat="option in isdom.scheduleOptions" value="{{option}}">{{option}}</option>
</select>
The person who has built the api end point is asking for the data in this format:
"outcomes": [
{ "itemNo": "is11", "outcome": "Pass" }
,
{ "itemNo": "is12", "outcome": "Pass" }...
How can I do this when my model is like so?
{
"isDom11": "N/A",
"isDOm12": "Pass",...
}
I thought about try to get all the elements in the model that start with isDom and pushing them into an outcomes array that has been modified into objects to copy the format required.
Is there a different way I can use ng-repeat to achieve this?
You could use ng-options for populating the select.
See: ngOptions or select
So it should be something like this:
$scope.isdom.scheduleOptions = [
{ "itemNo": "is11", "outcome": "N/A" }
,
{ "itemNo": "is12", "outcome": "Pass" }
];
<select ng-model="isdom.isdomForm.isDom101"
ng-options="item as item.outcome for item in isdom.scheduleOptions track by item.itemNo"></select>
Try using the (key, value) syntax as given in angular docs.
Key value in ng-repeat
(key, value) in expression –
where key and value can be any user defined identifiers, and expression is the scope expression giving the collection to enumerate.
For example: (name, age) in {'adam':10, 'amalie':12}.
Your example,
isdom.scheduleOptions = {
"isDom11": "N/A",
"isDOm12": "Pass",...
}
<select ng-model="isdom.outcomes">
<option ng-repeat="(itemNo, outcome) in isdom.scheduleOptions" value="{{outcome}}">{{outcome}}</option>
</select>

Bind <select> with ng-options and ng-model where model has composite key

I have an Angular service that returns a list of objects that have a "composite" key made up of two parts. I don't see how I can write the bindings so that they properly re-bind existing data. Here's my current attempt:
angular.module("app", [])
.controller("fooCtrl", function() {
// This comes from an Angular service / back-end:
this.options = [
{ part1: 3, part2: 101, displayName: "Option 3-101" },
{ part1: 4, part2: 651, displayName: "Option 4-651" },
{ part1: 4, part2: 999, displayName: "Option 4-999" }
];
this.item = { selectedOption: { part1: 4, part2: 651 } };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app="app" ng-controller="fooCtrl as vm">
<select ng-options="option.displayName for option in vm.options track by part1 + '-' + part2"
ng-model="vm.item.selectedOption"></select>
<hr>
Debug info:
<pre>{{vm.item | json}}</pre>
</div>
However, the above does not work: it should be selecting "Option 4-651" on loading, but doesn't do this.
Note that the displayName is added client side to the options, but it is not in the selectedOption when it is loaded. I don't mind if the selectedOption becomes an object that does have the displayName property, the back-end will just ignore it anyways because there is no equivalent backing property for it (I use C# in the back-end, the server-side DTO has no displayName property).
Important: I'm trying to do this without changing the loading in the javascript and structure of the options and selectedOption. Specifically:
I understand I can put some logic at the end of the controller method to "reset" this.item to a reference to the actual entry in options, but in my real code it's not so trivial (for one because async loading of options and selectedOption is involved).
I also understand I could change both the selectedOption and individual options so the "composite key" is also available as a "single compound key" e.g. part1and2: "3-101", but this requires me to admit (knowing that) I have an XY-Problem: I can't easily change the structure of those, because I'm cheating by binding my UI to the DTOs coming from the back-end, instead of having a proper view model to bridge the gap.
Is there a way to do this with a track by expression, i.e. is there a way to elegantly solve this in the binding expressions? Or do I have to resort to fixing this in controller or service code?
A simple solution would be that you restructure the your JavaScript object before you bind it so that it will have another property called part12 for example, and then track by that property :)
If the displayName is part of the JSON response then you should add that aswell to the selectedOption when you set the option in the controller.
Here's a working example of how you could do it without it (if you have the display name in the default selectedOption then add "option as option.displayName.." instead)
angular.module("app", [])
.controller("fooCtrl", function() {
// This comes from an Angular service / back-end:
this.options = [
{ part1: 3, part2: 101, displayName: "Option 3-101" },
{ part1: 4, part2: 651, displayName: "Option 4-651" },
{ part1: 4, part2: 999, displayName: "Option 4-999" }
];
this.item = { selectedOption: { part1: 4, part2: 651} };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app="app" ng-controller="fooCtrl as vm">
<select ng-options="option as ('Option ' + option.part1 + '-' + option.part2) for option in vm.options track by (option.part1 +'-'+ option.part2)"
ng-model="vm.item.selectedOption"></select>
<hr>
Debug info:
<pre>{{vm.item | json}}</pre>
</div>

How to use ng-options to set default value of select element reading from object?

I have the following data:
$scope.users = [
{
'id': 0,
'name': 'Tom'
},
{
'id': 1,
'name': 'Jack'
}
];
And I have a default object that is dynamically generated.
$scope.default = {
'id': 1,
'name': 'Jack'
}
I'm trying to set a default selected option in my ng-options based on $scope.default but because it's an object as opposed to a string, it doesn't seem to work.
<select ng-options="user.name for user in users" ng-model="default.name"></select>
I'm aware of this other question, but it doesn't work with objects.
how to use ng-option to set default value of select element
You can to use "as" and "track by" to define the label and the field to be compared:
<select ng-options="user as user.name for user in users track by user.id" ng-model="default"></select>
see the jsbin
Check out https://docs.angularjs.org/api/ng/directive/ngInit
or try:
If it's dynamic ordering, then you could track by a custom field, user.orderNum or something you can alter. I haven't tested, but should get you in the right direction.
By default, ngModel watches the model by reference, not value. Try
<select ng-options="user.name for user in users track by user.name " ng-model="default.name"></select>.
More here

Dropdown list display [object object] instead of value using knockout

I am using knockout to try to bind data into a dropdown list but for some reason i am only seeing [object][object] instead of the actual value i want to display and not sure what i could be doing wrong. This is what i have so far:
self.views = ko.observableArray();
self.selectedView = ko.observable();
if (views){
for(viewOption = 0; viewOption < views.length; viewOption++){
self.views.push(
new viewModel(views[viewOption])
);
}
}
//Sample data
var sampleData = {
viewers: [
.....
],
views: [
{
vValue: 'View 1'
},
{
vValue: 'View 2'
}
]
};
//HTML
<select data-bind="options: views, value: selectedView"></select>
When i run this i get a dropdown displaying the right count of options but instead of showing View 1 and View 2 it shows [object][object] twice.
When you are using objects in array, you should use optionsText for option label and optionsValue for option value.
var vm = {
myItems: [
{ vValue: 'View 1', id: 1},
{ vValue: 'View 3', id: 3},
{ vValue: 'View 4', id: 4}
],
selected: ko.observable()
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="
options: myItems,
optionsText: 'vValue',
optionsValue: 'id',
value:selected" >
</select>
<br/>
Selected: <label data-bind="text: selected"></label>
Since you are supplying an array of complex types to the options binding, Knockout does not know what value you want to use as the "text" of your option item (even though you only have a single name/value pair). In most real-world scenarios, you would have more than just a text value in array of complex types.
You can either use the optionsText binding to instruct Knockout to use your value in the name/value pair of vValue, like this:
<select data-bind="options: views, value: selectedView, optionsText: 'vValue'">
</select>
Another way to handle this is to create the views array in your view model to just be an array of strings, then Knockout knows that the single string value in the array is the value to use as the option's text value.
UPDATE
You can just create a JavaScript array of strings, like this:
self.views = ["View1", "View2"];
Then you can keep your options binding syntax the same, as you do not have to bind to an observable array in Knockout, you can bind to just a plain ol' JavaScript array.
Note - Usually people have an observableArray, because their data is dynamic (either through loading from the server or user interaction), but there is no rule that bound objects must be "observable"; although you will not get two-way binding for something like a text input if you bind to a non-observable.

Angular select tag with options and object comparison

I'm trying to set up a <select> tag with a pre-selected value. Unfortunately, I can't use the ng-options directive because the ui-select2 module doesn't support it.
Here's an example (or, as a Plunker if you would prefer):
// Controller
$scope.colors = [{
name: 'blue',
}, {
name: 'red',
}, {
name: 'green'
}];
$scope.selectedColor = $scope.colors[0];
<!-- HTML -->
<select ng-model="selectedColor">
<option ng-repeat="color in colors" value="{{color}}">{{color.name}}</option>
</select>
In this instance I would expect angular to realise that $scope.selectedColor is the same object as the first color object and preselect correctly but it doesn't appear to work.
I can solve this problem by using ng-options or by comparing by name but neither of these solutions are ideal.
How can I correctly compare objects in Angular selects?
I found an example online which seemed to use ng-options with ui-select2 and it seems to work fine with what you require. See Plunker here.
HTML
<select ui-select2
ng-model="selectedColor"
ng-options="color.name for color in colors">
</select>
Controller
$scope.colors = [
{
name: 'blue',
},
{
name: 'red',
},
{
name: 'green'
}];
$scope.selectedColor = $scope.colors[1];

Categories

Resources