I ran into a case where selecting of an option that is data bound to my javascript data object resulted into a different option being shown as selected.
Example data object:
var data = {
"person": { "no" : 2 },
"options": [
{"no":0,"t":"null"},
{"no":1,"t":"a"},
{"no":2,"t":"b"},
{"no":3,"t":"c"}
]
};
Corresponding Select with the data binding setup:
<script id="SelectTemplate" type="text/x-jsrender">
<select id="MySelect" data-link="person.no">
<option value=""></option>
{^{for options}}
<option data-link="{:t} value{:no} selected{:no === ~root.person.no}"></option>
{{/for}}
</select>
</script>
I have created a JsFiddle here to play with my setup. Can anyone please explain to me why this is happening? Or what I am doing wrong?
Note: I would like to share my current workaround just in case someone else happens to run into this problem. I am listening to property change event on my select data bound object (i.e. person). Here is what it looks like:
$(data.person).on('propertyChange', function (event, eventArgs) {
$("#MySelect").val(eventArgs.value);
});
The problem is that you are using integer values: no:1
rather than no:"1"
.
Those values get converted to string when set as values of the corresponding option element. So when the user selects a new item, the value person.no is set to a string "2"
, say, which fails the comparison :no === ~root.person.no
.
So here are four alternative fixes:
1: If you don't want to support having dynamic changes to the t
or no
values, then you don't need to data-link those values on the option, but can set them statically in the initial rendering:
<select data-link="person.no">
{^{for options}}
<option value="{{:no}}">{{:t}}</option>
{{/for}}
</select>
-but person.no
will still get switched to a string value after selection, unless you use a converter: <select data-link="{:person.no:toNum}">
(see #4 below...)
2: If you want to keep the data-bound values, you can change from using from integers to using string values.
3: Keep the integers and simply make the comparison non-strict: <option data-link="{:t} value{:no} selected{:no == ~root.person.no}"></option>
- but again, person.no
will get switched to a string value after selection...
4: Keep the integers and convert back to integer, so the number type is preserved:
$.views.converters("toNum", function(val) {
return +val;
})
and
<select data-link="{:person.no:toNum}">
{^{for options}}
<option data-link="{:t} value{:no} selected{:no === ~root.person.no}"></option>
{{/for}}
</select>
(So now person.no
will have a number value after selection...)
BTW - side note: for your workaround you could have used an alternative - specific for changes to person.no
, so it will not break if other properties of person
get changed:
$.observe(data.person, "no", function (event, eventArgs) {
$("#MySelect").val(eventArgs.value);
});
rather than
$(data.person).on('propertyChange', function (event, eventArgs) {
$("#MySelect").val(eventArgs.value);
});