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/
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
So if you upgrade to Knockout.js 3.1 you can write
Demo JSFIddle.