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

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.

Related

get select value from a drop with angulars reads error

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:

Dynamically using ng-selected for <select> tag with data loaded from server

I am trying to properly set a series of SELECT objects that are dynamically created in angular. The server returns an array of objects that I create these dropdowns from.
What I'd like to do is, for every dropdown created, assign the default selected value (as in, set ng-selected) based on the value of the object's value (labelled 'package')
The function changeValue changes the data on the server successfully.
Here is the code so far:
<!-- HTML -->
<div ng-repeat="package in bucket.packages">
<select ng-options='option.value as option.name for option in sources' ng-change="changeValue('source', package.id, selection)" ng-model="selection"></select>
</div>
//js
$scope.sources = [
{name: 'License Source'},
{name: 'Project Website', value: 'projectWebsite'},
{name: 'File', value: 'file'},
{name: 'Expected License', value: 'expectedLicense'}
];
$scope.optionMatches = function (selection, option){
return selection === option.value;
};
//not sure where to put this
ng-selected="optionMatches(package, option)"

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

Update entire object with value binding on select with knockout.js?

I have a select dropdown menu which shows a list of objects, with the name property being the text displayed, the id property being the value each option is bound to, and a value: user.id binding which is from a separate property on another object.
<td data-bind=""><select data-bind="options: peopleResponsible, optionsText: 'name', optionsValue: 'id', value: user.id"></select></td>
When I select a new person object from the dropdown list, only the id on the user is being updated. All of the other properties (name, username, age, etc) are not being updated.
What I need for it to do is when a new peopleResponsible option is selected, I want it to copy across all of the properties from that object to the user object.
I have a suspicion that at the moment it currently does not work because the user object itself is not observable, only its properties are. Here is how my data is being mapped:
ko.mapping.fromJS(taskOutlines, {}, mappedTaskOutlines);
Where a TaskOutline contains many Tasks, and each Task contains a single User.
Any ideas?
You can do this:
var vm = {
peopleResponsible: ko.observableArray([{
id: ko.observable(1),
name: ko.observable("p1")
}, {
id: ko.observable(2),
name: ko.observable("p2")
}, {
id: ko.observable(3),
name: ko.observable("p3")
}]),
selectedUser: ko.observable()
}
vm.selectedUser(vm.peopleResponsible()[1]); // pre select a user
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="options: peopleResponsible, optionsText: 'name', value: selectedUser"></select>
<div data-bind="with: selectedUser">
<p>Id:
<label data-bind="text: id"></label>
</p>
<p>Name:
<label data-bind="text: name"></label>
</p>
</div>
When a selection is made that selection will be a reference to the arbitrary object in the observable array, properties and all. This selected object will then be placed in "selectedUser" observable.
So in short, removing the "optionsValue" binding will bind the entire object instead of the id property.
The value binding only sets one observable. Not knowing how things are used, it's hard to say what you should do to get the result you want. One possibility is to make a function that does the copying and subscribe to the user.id.

AngularJS Push in Collection, Show from Collection, $watch changes

I use object ITEMS to hold data
$scope.items = [
{value:'title1', text: 'head1',
value:'title2', text: 'head2',
value:'title3', text: 'head3' }
];
When I clicked 'Add option' button I need show 'value' and 'text' in HTML page:
$scope.items.push(
{
value: 'value1',
text: 'text1'
}
);
I can show object length, but I can't show added option.
And $watch ($watchCollection) doesn't work too.
In this example I don't get values from inputs.
enter link description here
Your $scope.items array is improperly declared. You need braces around each separate item in the array, like this:
$scope.items = [
{value:'title1', text: 'head1'},
{value:'title2', text: 'head2'},
{value:'title3', text: 'head3'}
];
Your directive is all kinds of messed up. You don't even need to create a new directive if all you want to do is display the items in a list. You can just do this:
<select ng-model="selectedItem" ng-options="item.text for item in items"></select>
Your textboxes are ok, except for the typo in the ng-model="addoText". Your labels below should be bound to the same variables as the textboxes.
key: {{addVal}} <br>and value: {{addText}}
That will update the labels as you type in the textboxes. If you don't want to update the labels until you add a new item, then bind them to some new variables, like this:
key: {{newVal}} <br>and value: {{newText}}
Finally, your add() function should look like this:
$scope.add = function () {
$scope.items.push(
{
value: $scope.addVal,
text: $scope.addText
}
);
$scope.newVal = $scope.addVal;
$scope.newText = $scope.addText;
};
This pushes the new item to the array, and sets the bindings on your labels to the new values. You don't need to $watch anything.
Here's a Plunker.
There is an issue with how your items array looks at the moment.
I think your $scope.items should look like:
$scope.items = [
{
value: "value1",
text: "text1"
},
{
value: "value2",
text: "text2"
}
]
rather than all in one object, as when you push you'll create a new object.
With your question, calling items.value, will result in an undefined.
You need to call an object in $scope.items. Calling items[$scope.items.length-1] will get the most recent object added, and such items[$scope.items.length-1].value and items[$scope.items.length-1].text the values in that object

Categories

Resources