I have this Javascript code for a dropdown list
$('#TravelG').append("<option value selected>Select TravelG</option>");
for (var i = 0; i < Travel.length; i++) {
$('#TravelG').append("<option value='" +
Travel[i].Id + "'>" + Travel[i].Name + "</option>");
}
I need to rewrite the above code in knockout as in I have this observable array,
viewModel.Travelname = ko.observableArray([]);
I need to populate this Travelname property of viewmodel as name , value pair and Travel is the object that contains the data. So that I can tie this Travelname property of a viewmodel to a dropdown. How do I achieve this ?
As correctly mentioned in comments by #hunch_hunch, you should use knockout options binding for this.
Suppose your Travel model looks like this:
function Travel(id, name) {
this.Id = id;
this.Name = name;
}
Then in your view model you have your observableArray with collection of Travel objects (this refers to view model):
this.Travelname = ko.observableArray([new Travel(1, 'Moscow'), new Travel(2, 'Paris'), new Travel(3, 'San Francisco')]);
The final part is your markup, which should be something like this:
<select data-bind="options: Travelname, optionsText: 'Name', optionsValue: 'Id', optionsCaption: 'Select travel...'"></select>
Here is final working demo. I've added simple functionality to add items to the list, so you would see how to do that.
Related
I have a list of statuses which are returned from an ajax call to a Ref Data service
I have this defined in my js file:
self.StatusIdList = ko.observableArray();
self.StatusTextList = ko.observableArray();
This is the success handler of my ajax call:
success: function (data, textStatus, message) {
$.each(data, function (index, item) {
self.StatusTextList.push(item.statusDescription);
self.StatusIdList.push(item.statusId);
});
},
This is what I have in my HTML
<select data-bind="options: StatusIdList, value: currentFormStatus, optionsText: StatusTextList" class="span12"></select>
If I set the options to StatusTextList then the dropdown is populated with the list of statuses as expected - however with it set to ID it is populated with the list of ids which I don't want.
So I attempted to use optionsText and was hoping it would then display the Name in the dropdown but keep the unique id per status at the option value but in the dropdown with my current code as above it is displaying as below:
<option value="1">[object Window]</option>
Where actually the unique id of statusId = 1 should be displayed as 'Order Received'
You don't need 2 separate arrays for populating the dropdown. Create an observableArray called StatusList with items which have both statusId and statusDescription properties. (more on options binding from KO website)
In your HTML:
<select data-bind="options: StatusList, value: currentFormStatus, optionsText: 'statusDescription', optionsValue: 'statusId', optionsCaption: 'Select'"></select>
The optionsText should point to whatever property in array, you want displayed as text in the dropdown. In our case it is statusDescription.
The optionsValue should point to the property which is value for the option. In this case it is statusId.
var viewModel = function (data) {
var self = this;
self.currentFormStatus = ko.observable();
self.StatusList = ko.observableArray([]);
// functions, ajax etc
};
In your success callback:
// you can push to the array in your callback like this
// each item in "data" should have "statusDescription" and "statusId" properties
success: function (data, textStatus, message) {
$.each(data, function (index, item) {
self.StatusList.push(item);
});
},
I have created a fiddle
I have a page that populates its fields(dropdowns and textboxes) from the DB when the page loads via VIEWDATA object from controller.
I am using KnockoutJS for data-binding, below is the scenario
HTML & JS(dropdown)
#if (Filter!= null)
{
<select data-bind="options: RsnAdmAct,
value: selectedRsnAdmAct,
optionsCaption:'Choose...',
optionsValue:'RsnAdminActionID',
optionsText:'RsnAdminActionDescp',
optionsAfterRender: function()
{
setOptionRSN(#Filter.RsnForAdminAction);
}">
</select>
}
self.RsnAdmAct = ko.observableArray([]);
self.selectedRsnAdmAct = ko.observable();
$.getJSON("GetRAA", null, function (data) {
self.RsnAdmAct(data);
});
self.selectedRsnAdmAct = ko.observable();
self.setOptionRSN = function (x) {//reason for admin action dd
self.selectedRsnAdmAct(x);
};
this does update the drop-down with the assigned value "X".
But the same does not assign value for the text-boxes as below
HTML & JS(textbox)
#if (#Filter != null)
{
<input placeholder="Downstream"
data-bind="value: DownStream,
optionsAfterRender:function()
{
setOptionDstream(#Filter.DownstreamNumber);
}">
}
self.DownStream = ko.observable();
self.setOptionDstream = function (x) {//down stream number
self.DownStream(x);
};
optionsAfterRender applies to options; a text input has no options. Setting the value of DownStream will set the value of the text box, because that's how the value binding works.
I tried to search for a proper way to do this but below is the way it works and no other alternative worked.I had to move the function which assigns the value to the texbox observable into the options after render attribute of the drop down as below
#if (Filter!= null)
{
<select data-bind="options: RsnAdmAct,
value: selectedRsnAdmAct,
optionsCaption:'Choose...',
optionsValue:'RsnAdminActionID',
optionsText:'RsnAdminActionDescp',
optionsAfterRender: function()
{
setOptionRSN(#Filter.RsnForAdminAction);
setOptionDstream(#Filter.DownstreamNumber);
}">
</select>
}
This is the only way it worked for me.Thank you for the posts and comments
I have a dropdown generated using ng-options
<select class="form-control" ng-options="item.value as item.label for item in filterFields track by item.value" ng-model="selectedFilterField">
</select>
The problem is that when I select an option from this dropwon, the selected item appears as empty and an extra blank element is added to the dropdown. What am I doing wrong?
Edit: added controller code:
$scope.columns = accountColumns;
$scope.filterFields = [];
$scope.filterFields.push(defaultSelectOption);
$scope.filterFieldValues.push(defaultSelectOption);
var idx = 1;
for(i=0; i < accountColumns.length; i++) {
var option = {label: accountColumns[i], value: accountColumns[i]};
$scope.filterFields.push(option);
}
$scope.selectedFilterField = $scope.filterFields[0];
Let's say your filterFields array has objects that look like this:
{
name: "",
value: 0
}
In your ng-options you tell angular that the possible values for the select is an array of these objects. But you also tell angular that when you select an option then the real value is the object.value; So now angular sees that this value is not present in the array of options and tries to add it or something.
Initially the dropdown works because you set the ng-model to a complete object present in the filterFields array.
Try it with this:
ng-options="item for item in filterFields track by item.value"
I'm using Knockout 3.2 and i'm trying to display a multiple select dropdown with some selected values, but the values are not being selected. The problem is that KO does not populate the 'value' attribute of the options:
<select data-bind="options: availableCountries, selectedOptions: chosenCountries, optionsText: 'name'" size="5" multiple="true">
<option value="">France</option>
<option value="">Germany</option>
<option value="">Spain</option>
</select>
VM:
var viewModel = {
availableCountries : ko.observableArray([{name:'France'}, {name:'Germany'}, {name:'Spain'}]),
chosenCountries : ko.observableArray(['Germany'])
};
If instead of object i turn availableCountries into a simple strings array, it works.
You can see a live sample here
var viewModel = {
availableCountries : ko.observableArray([{name:'France'}, {name:'Germany'}, {name:'Spain'}]),
chosenCountries : ko.observableArray(['Germany'])
};
['Germany'] is not {name: 'Germany'}!
And also if you, would write chosenCountries : ko.observableArray([{name: 'Germany'}]), this would lead to two different objects, with the same property name and the value 'Germany'.
var viewModel = (function() {
var self = {};
self.availableCountries = ko.observableArray([{name:'France'}, {name:'Germany'}, {name:'Spain'}]);
self.chosenCountries = ko.observableArray([self.availableCountries()[1]]);
return self;
})();
ko.applyBindings(viewModel);
I changed the viewModel, to an instand called function which returns the viewModel.
(function () {...})()<-call
http://jsbin.com/monasijufaya/1/edit?html,js,output
I am working on a drop down menu within a TR .. I have true, false or none as the value that I receive from server and I want that to change the drop down option as in example below.
The first one is working but I want the second one to function as the first one
Example is here: http://jsfiddle.net/3xLgJ/
This is my HTML:
<div data-bind='text: incomingValue'></div>
<select data-bind="value: incomingValue">
<option value="true">Yes</option>
<option value="false">No</option>
<option value="none">Don't Know</option>
</select>
How can I implment this as above as this is within a tr and to function as above
<select data-bind='options: yesno, value: incomingValue'/>
Here is my knockout
var myModelView = function () {
self = this;
self.yesno = ko.observableArray(['Yes', 'No', 'Don\'t know']);
self.incomingValue = ko.observable('none');
};
var moView = new myModelView();
ko.applyBindings(moView);
Thanks
Thanks
The best solution is probably to slightly reconstruct the view model to use objects instead of simple strings:
// Create a "class" that represents an option
var Option = function(id, caption) {
this.id = id;
this.caption = caption;
};
Now you populate the observable array with objects constructed from this function:
self.yesno = ko.observableArray([
new Option('true', 'Yes'),
new Option('false', 'No'),
new Option('none', 'Don\'t know')
]);
You can use the "optionsText" binding to correctly bind these objects to the markup:
<select data-bind="options: yesno,
optionsText: 'caption',
value: selectedItem"></select>
If you receive a string "none" from the server, you need to find the object representing this option:
var incomingValue = 'none';
// Find the first object that is a match in the observable array "yesno"
var incomingItem = ko.utils.arrayFirst(self.yesno(), function(item) {
return item.id == incomingValue;
});
self.selectedItem = ko.observable(incomingItem);
When displaying the selection somewhere else you'll need to consider that the selection is represented by an object:
<div data-bind='text: selectedItem().caption'></div>
Demo: http://jsfiddle.net/3xLgJ/2/
You need to use the optionsText and optionsValue bindings. You'll need to make an observable array of values and text:
self.yesno = ko.observableArray([
{value:"true",text:"Yes"},
{value:"false",text:"No"},
{value:"none",text:"Don't Know"}]);
then, you need to do something like this in your html:
<select data-bind="options: yesno2, optionsText: 'text',optionsValue: 'value', value: incomingValue"></select>
See here for a working example