I am using knockout to create a select element, the options have to be set late (the options are set by loaded them from a server). This is causing the initial value to be lost. Below I have some working code it does what I want, but with the loading from server replaced with a static table.
If the line setupSelect();
is moved to the end of the script (this simulates the asynchronous ajax call to the server), then the select asks me to choose.
I think that when there are no choices the value is overwritten, then the choices arrive, but the value is now null.
It looks like I know what the problem is, but don't know how to get it to work.
Can you tell me how to get it to work?
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js" ></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>
</head>
<body>
<p>
Your thing:
<select data-bind="options: (function(){return $root.select1.rows;})(),
optionsText: function(item){return item.name;},
optionsValue: function(item){return item.id;},
value: selectedThing1,
optionsCaption: 'Choose...'">
</select>
<span data-bind="visible: selectedThing1">
You have chosen a thing with id
<span data-bind="text: selectedThing1() ?
selectedThing1() :
'unknown'">
</span>.
</span>
</p>
<script type="text/javascript">
var viewModel = {
select: {rows: ko.observableArray() },
selectedThing : ko.observable() // Nothing selected by default
};
function setupSelect(){
//in the real application rows_raw is populated from a server using $.ajax
var rows_raw= [
{name: "a thing", id:1},
{name: "one more thing", id:2},
{name: "another thing", id:3}
];
$.each(rows_raw, function(index, item){
viewModel.select.rows.push(item);
});
}
//setupSelect(); //when loading from server (using $.ajax in async mode), then this line is effectivly moved to the end of the script.
viewModel.selectedThing(2); //set ititial value
ko.applyBindings(viewModel);
setupSelect(); //when loading from server (using $.ajax in async mode), then this line is effectivly moved to the end of the script.
</script>
</body>
</html>
You can also see both examples here http://jsfiddle.net/V33NT/1/
To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.
The $data variable is a built-in variable used to refer to the current object being bound. In the example this is the one of the elements in the viewModel.
KO is able to create a two-way binding if you use value to link a form element to an Observable property, so that the changes between them are exchanged among them. If you refer a simple property on ViewModel, KO will set the form element's initial state to property value.
Essentially a binding or a data binding is a way to link your ViewModels to your Views(templates) and vice versa. KnockoutJS uses two-way data binding, which means changes to your ViewModel influence the View and changes to your View can influence the ViewModel.
KnockoutJS - Options Binding. This binding is used to define the options for a select element. This can be used for either drop-down list or a multi-select list. This binding cannot be used with anything other than <select> elements.
You can even nest options within <optgroup> elements and Knockout will set the selected value appropriately. Normally, when you use the value binding on a <select> element, it means that you want the associated model value to describe which item in the <select> is selected.
Knockout has special support for drop-down lists (i.e., <select> elements). The value binding works in conjunction with the options binding to let you read and write values that are arbitrary JavaScript objects, not just string values. This is very useful if you want to let the user select from a set of model objects.
If you are trying to bind an <input type="text" /> or <textarea> to get instant updates to your viewmodel, use the the textInput binding. It has better support for browser edge cases than any combination of valueUpdate options. Knockout has special support for drop-down lists (i.e., <select> elements).
This is default bahavior: Knockout forces the value to match an existing option, if there is no existings option it unsets the observable.
However there is new setting in KO 3.1. which is called valueAllowUnset
and it is addressing exactly this scenario.
From Knockout.js 3.1 Released
- With this option set to true, Knockout does not force the value to match an existing option.
- The selection will be set to an empty option in the case of a mismatch, but the value is not overwritten.
- This is very useful in scenarios where options are lazily loaded and there is an existing value.
So if you upgrade to Knockout.js 3.1 you can write
<select data-bind="options: (function(){return $root.select2.rows;})(),
optionsText: function(item){return item.name;},
optionsValue: function(item){return item.id;},
value: selectedThing2,
valueAllowUnset: true,
optionsCaption: 'Choose...'">
Demo JSFIddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With