In the HTML markup I declare the combobox and bind it to the datasource with the following
<input
id="viewRequest_drpBroker"
data-role="combobox"
data-text-field="ClientName"
data-value-field="ClientID"
data-bind="source: BrokersDatasource, value: InspectionRequest.BrokerID"
/>
The list is populated correctly, the datasource is bound, the proper text appears, however the ClientID is not being bound as the value. On selection of a combobox item I am expecting the ClientID to be reflected in the viewmodels InspectionRequest.BrokerID. However instead of setting the ClientID, it is setting the entire ClientListItem instance to the BrokerID. So the actual BrokerID value is something like '{ClientName: "Generic Broker", ClientID: "44"}', when in fact it should just be "44".
The issue only occurs one way. If I set the BrokerID using viewmodel.set("InspectionRequest.BrokerID", 44), it will find and toggle the correct list item and text in the widget. However when selecting from GUI/Widget it sets the BrokerID to entire instance of the object instead of just numeric value.
The bug is present in both the latest commercial release(2012.1.515) and latest internal build(2012.1.615). I have used autocomplete and dropdownlists in a similar way with no issues encountered.
14 Answers, 1 is accepted
I will continue stepping through the Javascript to see what I find.
I found the section of code that is changing the value. It is in the "kendo.binder.js" file
change:
function
() {
var
value =
this
.widget.value();
var
idx, length;
var
field =
this
.options.dataValueField ||
this
.options.dataTextField;
if
(field) {
var
source,
isObservableObject =
this
._valueIsObservableObject;
if
(
this
.bindings.source) {
source =
this
.bindings.source.get();
}
if
(value ===
""
&& isObservableObject) {
value =
null
;
}
else
{
if
(!source || source
instanceof
kendo.data.DataSource) {
source =
this
.widget.dataSource.view();
}
for
(idx = 0, length = source.length; idx < length; idx++) {
if
(source[idx].get(field) == value) {
if
(isObservableObject) {
value = source[idx];
}
else
{
value = source[idx].get(field);
}
break
;
}
}
}
}
this
.bindings.value.set(value);
}
On the first line "var value = this.widget.value();" it is finding the correct value of the drop down list.
However inside the for loop it is reassigning the value to the instance of the selected datasource item, instead of the items value.
if
(isObservableObject) {
value = source[idx];
}
Please correct this bug in next internal build, or please advise if my implementation is incorrect.
This is actually not a bug. This behavior is by design. The value binding will use the whole object which is currently selected in the combobox not just the value field. We can't change this behavior because quite a lot of customers currently rely on it.
Regards,Atanas Korchev
the Telerik team
In the case you want to bind an entire instance rather than just the value, then the data-value-field should be omitted or it should require a keyword such as self/this. It makes logical sense that the data-value-field would become the value... So beyond an inconsistent two way behaviour there is an ambiguous naming convention.
Breaking changes get implemented all the time, this would be a justified situation and if the logic cannot change then an enhancements should be added to allow binding of the value field using a different property name.
If you already have an alternative method of binding where I can bind only the value field, please advise.
The data-value-field is required to determine which object should the selected value point to. There is a workaround to have the value be the "data-value-field" itself. The workaround is to set the initial value to some primitive type: string, number. Here is a demo: http://jsfiddle.net/korchev/DWUnx/4/
Regards,Atanas Korchev
the Telerik team
Using the proposed work around there are 4 issues.
1. Default value cannot be null, which is required.
2. When combo box is cleared it defaults value to an empty string which is not a supported numeric type and will cause deserialization to fail. Value must be null or numeric.
3. Initializing with a numeric value such as 0, will print the value in the textbox since it does not exist in the list.
4. Placeholders will not work
I think this should be a configurable option, rather than initializing with a null/notnull variable.
Here are some suggestions:
1. Add new widget property which allows to specify empty value. Instead of just placeholder you would instead have placeholder-text, and placeholder-value. So you can choose null, empty string, 0, etc.... This takes care of nullable types.
2. Allow override of IsObservable so that in the markup you can specify to bind a value instead of observable object.
I am afraid that we cannot suggest any immediate workaround than the one from my previous reply. We also can't change the implementation overnight without breaking existing customer's applications.
I suggest you open a new user voice item to request a change in this behavior. We will act according to the number of votes this feature gets.
Atanas Korchev
the Telerik team
My solution was to bind a change handler and set the value to the field of the object I wanted.
It's not pretty, but it worked ok.
myModelVariable.bind(
"change"
,
function
(e) {
// Drop down lists return the entire object as the value
// but that is not what we want in the field. Just the dataValue field is required
if
(e.field ==
"MyModelFieldName"
) {
var
val = myModelVariable
.get(e.field);
// Do not use Set mothod as this will fire this event again!
if
(!(
typeof
val ===
'undefined'
)) {
myModelVariable
.MyModelField = val.MyValueFieldValue;
}
}
});
I never did end up creating a User Voice thread, it seems a bit ridiculous that paying customers get the same voting power as everyone else. So much for premium support!
Anyway, it looks like someone else posted a UserVoice thread for this exact issue and it has 35 votes.
http://feedback.kendoui.com/forums/127393-kendo-ui-feedback/suggestions/3356384-dropdown-null-values
Telerik releases breaking changes all the time, especially with reports. This is a relatively small change in comparison, so I don't see why there is so much reluctance. Anyway I don't have the patience to argue the point anymore, just going to stick with the workaround.
I came across this thread looking into a similar problem and I'm curious about this behavior. You listed the jsFiddle at http://jsfiddle.net/korchev/DWUnx/4/ and based on that I modified it to this one: http://jsfiddle.net/danielrdevine/4zEAY/2/
I'm confused about the behavior in my version. I understand that you end up with the whole object bound for items 1 and 2, but why not for the null one? In my application, we were relying on something similar to the selectedProductID.id property holding the value, but we don't get an object with id = null, we get a null in place of the object and selectedProductID.id is undefined. It's like a weird combination of the 2 modes (binding to the object vs. value). Thanks in advance for any clarity you can provide.
I updated the fiddle to the latest version (it was two versions behind) and it seems to work better: http://jsfiddle.net/4zEAY/3/
Regards,Atanas Korchev
the Telerik team
That does look better in one way I hadn't really noticed. When you go back to selecting the null value it puts the correct -Select- text in the box instead of null.
However, it appears that the odd behavior persists even in the new version (which, by the way is what I'm developing on, didn't notice it was an older version in the fiddle). You can see what I mean by binding the span to selectedProductID instead of selectedProductID.id. When you do that, you'll see the objects for the Food and Drinks products, but when you select the null one, you just get a null and not an object with an id of null.
I think this illustrates it: http://jsfiddle.net/danielrdevine/T48WH/1/
This doesn't work because the combobox's value is always a string. In this case the value is the string "null". Since "null" != null it cannot find the right value from the products array. It works with numbers because "1" == 1 in JavaScript.
I have two suggestions
- use a different value for the - Select- item - for example 0.
- avoid having an extra item altogether and rely on the combobox' placeholder: http://jsfiddle.net/T48WH/2/
Atanas Korchev
the Telerik team
Ok, I think I understand now. It's a bit confusing how it binds either the object or the specific value inside the object based on the initial value, especially in the null != "null" case (didn't realize it was always comparing to a string version). Thanks for the clarification.