3

I have a kendoUI dropdownlist that is in a template and is bound to a ViewModel, along with a span that is bound to the data item that is selected in the dropdownlist:

<p>
    <label>Appointment Type: </label>
    <select id="appointmentTypeDropDownList"
            data-text-field="Name"
            data-value-field="AppointmentTypeId"
            data-role="dropdownlist"
            data-bind="source:appointmentTypes, value:AppointmentTypeId"
            data-autobind="true"
            data-select="onSelected" />
</p>
<p><label>Duration:</label>
    <span data-bind="text:selectedAppointment.Duration"></span> minutes
</p>

My ViewModel:

var viewModel = new kendo.observable({
    appointmentTypes: appointmentTypesDataSource,
    selectedAppointment : null,
});

Originally, I was using a hardcoded array of appointmentTypes, and setting the selectedAppointment to appointmentTypes[0] in the above viewModel declaration. That doesn't work now, because the datasource loads asynchronously. The viewModel is updated in the onSelected function:

var onSelected = function (e) {
    var dataItem = this.dataItem(e.item.index());
    viewModel.set("selectedAppointment", dataItem);
};

The template is in a window, and the span is empty the first time it loads, and then works thereafter (once the data has loaded from the first request).

My question is, how can I get the data binding of the span to work on the first request, so that it will display the Duration of the currently selected appointmentType from the list that is returned by the data source? Do I try and bind it to the selected data item of the dropdownlist? Is there a callback somewhere I should be using to do this? The template is inside of a kendoScheduler, if that matters:

var template = kendo.template($("#editor").html());

$("#scheduler").kendoScheduler({
    editable: {
        template: template()
    }
});

Thanks!

Update: The template I've been working with is an editor for a Kendo UI Scheduler, which was not bound to its viewmodel, but was using part of the viewmodel for its datasource. In this case, trying to use the data-bind="events:{...}" syntax was causing the weird type errors I was getting. To wire up the databound event, Atanas let me know to use data-bound="onDataBound" and a global handler function (or alternately to configure my scheduler declaratively and bind it to the viewmodel). Using data-bound combined with the answer(s) below worked for me.

ssmith
  • 8,092
  • 6
  • 52
  • 93
  • What is the desired initial value of selectedAppointment? How do you determine it from the data source? Obviously you don't want it to be null. – Atanas Korchev Feb 15 '14 at 16:55
  • It should match the first item in the dropdownlist, since if the user does nothing but save the form, the first item in the dropdownlist will be the selectedvalue. – ssmith Feb 15 '14 at 17:01

2 Answers2

4

You could use the dataBound event on the dropdown and set selectedAppointment from there:

data-bind="source:appointmentTypes, value:AppointmentTypeId, events: { dataBound: onDataBound }"

and your view model:

var viewModel = new kendo.observable({
    appointmentTypes: appointmentTypesDataSource,
    selectedAppointment : null,
    onDataBound: function(e) {
        e.sender.select(0); // will trigger your change handler
    }
});
Lars Höppner
  • 18,252
  • 2
  • 45
  • 73
  • Trying to get this working but getting error "Uncaught TypeError: undefined is not a function" which seems to occur in the declarative initialization. I've tried it with onDataBound on my viewModel as shown and as a global variable; same effect. Any ideas? Thanks. – ssmith Feb 13 '14 at 04:59
  • also why can i use data-select for the select event, but not data-databound for the databound event? – ssmith Feb 13 '14 at 05:01
  • This jsFiddle implies the databound binding is not available for the DropDownList widget: http://jsfiddle.net/7GE3b/1/ – ssmith Feb 13 '14 at 05:20
  • I set up a demo [here](http://plnkr.co/edit/kpQzzY9xWLxpt5aOlRj3?p=preview); your jsfiddle is probably not working because it's using a pretty old version of kendo ui; re your question: if you want to bind methods on the view model to events, you need to do it in data-bind (if you set it up with data-select, it'll only look for the function in the global scope) – Lars Höppner Feb 13 '14 at 05:28
  • No worries regarding edit. Updated jsfiddle to latest KendoUI and jQuery 1.9.1 here. http://jsfiddle.net/7GE3b/3/ Error is now: Uncaught Error: The dataBound binding is not supported by the DropDownList widget. Thanks again. – ssmith Feb 13 '14 at 14:55
  • You used "events =" but it should be "events:" - check [my plnkr](http://plnkr.co/edit/kpQzzY9xWLxpt5aOlRj3?p=preview) again; I also updated [your fiddle](http://jsfiddle.net/lhoeppner/7GE3b/5/) – Lars Höppner Feb 13 '14 at 15:44
  • really? a stinkin' little colon caused him all that grief? ;) – Julie Lerman Feb 13 '14 at 20:59
  • Thanks Lars - I'll try and apply the Plnkr (which works great!) to my actual code this evening, and will likely mark this as the answer. – ssmith Feb 13 '14 at 21:37
  • 1
    @Julie I keep arguing with my computer "My _intentions_ were obvious! Surely, you must know what I _meant_?"; but he always scoffs and throws exceptions and other obscenities at me. Sometimes I wonder whether he takes me seriously at all. – Lars Höppner Feb 14 '14 at 01:08
  • re your last comment, Lars: "like" oh, I mean "like:" :) – Julie Lerman Feb 14 '14 at 19:41
1

You need to set the initial value of the selectedAppointment. This is the only way the span text will be set before the data source has been populated. Here is a runnable demo based on Northwind's Products:

<span data-bind="text:selectedProduct.ProductName"></span>
<select data-bind="source: products, value: selectedProduct"
      data-text-field="ProductName"
      data-value-field="ProductID"
      data-role="dropdownlist"></select>
<script>
var o = kendo.observable({
  selectedProduct: {
    ProductID: 2,
    ProductName: "Chang"
  },
  products: new kendo.data.DataSource({
    transport: {
      read: {
        url: "http://demos.telerik.com/kendo-ui/service/products",
        dataType: "jsonp"
      }
    }
  })
});

kendo.bind(document.body, o);
</script>

Here is a live demo: http://jsbin.com/pawiz/1/edit

Atanas Korchev
  • 30,562
  • 8
  • 59
  • 93
  • What about this example Lars showed: http://plnkr.co/edit/kpQzzY9xWLxpt5aOlRj3?p=preview ? I haven't been able to get it to work in my actual code because I'm always getting the "Uncaught TypeError: undefined is not a function" error in my events:{} binding, but it clearly works in his demo. I can get it working with your code, but that's clearly a hack, since I now have to embed magic values in my client script instead of relying on the actual data from the datasource. Thanks! – ssmith Feb 15 '14 at 16:22
  • Why is this clearly a hack? Where does the "value" come from in your real scenario? Isn't it a property of something else? A data source doesn't support "selected value" on its own - it just represents an array of items. The linked example always selects the first data item once data has been received. – Atanas Korchev Feb 15 '14 at 16:50
  • Since the dropdownlist doesn't have an empty first item (e.g. "choose an item"), whatever the first item is, is the default item. By this same convention, whatever the first item is in the dropdownlist's datasource, should be the default selectedItem in the viewmodel (with its Duration property in my case shown in the bound span). It's a hack to include names/IDs from the datasource in the client code since I might change datasources in the future, or the order of that data might change, and my code will be incorrect unless I update the hardcoded values. – ssmith Feb 15 '14 at 16:57
  • In your example, if someone adds a new product that is listed before "Chang", let's say "Asparagus". Now, the span will read "Chang" but the first item in the dropdownlist will read "Asparagus", right? – ssmith Feb 15 '14 at 16:59
  • No. Both will stay the same - Chang. Unless the new item has the same ProductID as Chang. Anyway if you don't want to set initial value you would have to do something like Lars did. Somehow trigger the change of the dropdownlist: http://jsbin.com/pawiz/2/edit – Atanas Korchev Feb 15 '14 at 17:04