How do I bind a DropDownList to a DataSource within an editor template using the scheduler? - kendo-ui

I'm trying to customize my use of the Kendo UI kendoScheduler widget. I'm specifying a custom template for the editable window that pops up when you go to add/edit an appointment in the scheduler, like so:
editable: {
template: $("#editor").html()
},
I'm defining the template like this:
<script id="editor" type="text/x-kendo-template">
<h3>Edit Appointment</h3>
<p>
<label>Patient: <input name="title" /></label>
</p>
<p>
<label>Start: <input data-role="datetimepicker" name="start" /></label>
</p>
</script>
So now I want to add a Kendo UI DropDownList and configure it to populate from a remote datasource. How do you configure such things within a template?
Sample code (does not work):
<p>
<label>Type: </label><input id="appointmentTypeDropDownList" />
</p>
# var dataSource = new kendo.data.DataSource({ transport: { read: { url: "http://demos.kendoui.com/service/products", dataType: "jsonp" } } });
# $("#appointmentTypeDropDownList").kendoDropDownList({ dataSource: dataSource, dataTextField: "ProductName", dataValueField: "ProductID" } ) ;
The error it gives with the above code is:
Uncaught Error: Invalid template:'
Probably this is just a script encoding issue; I'm more interested in the proper way to place a bound DropDownList inside of a template.
Update - The latest simplified version of what I'm trying to do is available at this jsfiddle URL. The goal is simply to bind the dropdown list in the most straightforward way possible. Thanks!

If you move your scheduler DataSource into your viewModel you can use the parenting functionality of a kendo Observable to have the DropDownList bind against the correct DataSource.
var viewModel = new kendo.observable({
appointmentTypes : new kendo.data.DataSource({
data: [{
id: 1,
text: "Wellness Exam"
}, {
id: 2,
text: "Diagnostic Exam"
}, {
id: 3,
text: "Nail Trim"
}]
}),
schedulerData: [{
id: 1,
start: new Date("2014/1/27 08:00 AM"),
end: new Date("2014/1/27 09:00 AM"),
title: "Breakfast"
}]
});
Now when you create the scheduler you just have it use the schedulerData property on the view model, as the DataSource for the scheduler.
$("#scheduler").kendoScheduler({
...
dataSource: viewModel.schedulerData,
...
});
The last piece is just changing your DropDownList declaration to use the appointmentTypes property on your view model.
<select id="appointmentTypeDropDownList" data-bind="source:appointmentTypes, value:id" data-text-field="text" data-value-field="id" data-role="dropdownlist" data-autobind="true" />
Since your template will be bound against the Observable objects in the schedulerData DataSource, Kendo will climb the parent tree of the object until it's able to resolve the appointmentTypes property that's on viewModel.

The template throws an error because the selector "#appointmentTypeDropDownList" should be escaped and look like this "\\#appointmentTypeDropDownList" (Kendo UI Documentation).
After you fix this you won't receive template errors but it still doesn't bind the data to the KendoDropDownList.
I checked what a KendoUI MVC helper will render in this case and it seems that if your template looks like this, it will work.
<script id="editor" type="text/x-kendo-template">
<h3>Edit meeting</h3>
<p>
<label>Title: <input name="title" /></label>
</p>
<p>
<label>Start: <input data-role="datetimepicker" name="start" /></label>
</p>
<p>
<label>Start: <input data-role="datetimepicker" name="end" /></label>
</p>
<p>
<label>Type: </label><input id="appointmentTypeDropDownList" />
<script>
var dataSource = new kendo.data.DataSource({ transport: { read: { url: "http://demos.kendoui.com/service/products", dataType: "jsonp" } } });
jQuery(function() { jQuery("\\#appointmentTypeDropDownList").kendoDropDownList({ dataSource: dataSource, dataTextField: "ProductName", dataValueField: "ProductID" } ); });
<\/script>
</p></script>

It's not necessary to put any javascript in the template, you can use Kendo's data-attribute initialization features.
So, your template would look something like:
<label>Type: </label>
<input id="appointmentTypeDropDownList" data-text-field="ProductName" data-value-field="ProductID" data-bind="value:ProductID" data-source="dataSource" data-role="dropdownlist" data-autobind="true" />
Then you would have Javascript outside of your template:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "http://demos.kendoui.com/service/products",
dataType: "jsonp"
}
}
});
As long as dataSource is defined globally, you're good to go. There's more info on data attribute initialization here http://docs.telerik.com/kendo-ui/getting-started/data-attribute-initialization
Edit: just noticed your comment "data will depend on the selected datetime". You could always try re-defining the datasource options in the edit event, which is called prior to displaying the popup editor window. I've not used this scenario, but I don't see why it wouldn't work.

Related

Adding Kendo Controls on Kendo Scheduler Custom Template

I have a Kendo Scheduler in MVC Core, and I need to open the custom popup on click of the events on calendar. I am able to add the Script tag and give ID and Call the template as pop up by using that ID.
Issue I have is when I try to add the kendo control within script it fails. normal buttons and labels work fine. Moment I add the Kendo Button it fails.
Can someone help on this one
CODE:
<script id="editor" type="text/x-kendo-template">
<h3>Edit meeting</h3>
<p>
<label>Title: <input name="title" /></label>
</p>
<p>
<label>Start: <input data-role="datetimepicker" name="start" /></label>
</p>
<p>
<label>Start: <input data-role="datetimepicker" name="end" /></label>
</p>
$("#scheduler").kendoScheduler({
date: new Date("2013/6/6"),
editable: {
template: $("#editor").html()
},
views: [
{ type: "day" }
],
dataSource: [
{
id: 1,
start: new Date("2013/6/6 08:00 AM"),
end: new Date("2013/6/6 09:00 AM"),
title: "Interview"
}
]
});
You should either use MVVM to create a custom editor or add an edit event handler, and when the event fires initialize a widget from a DOM element in the template. Example

kendojs template data-bind click event not working

Well, I am using KendoJS grid and I have this code here in my .js file:
var viewModel = kendo.observable({
people: new kendo.data.DataSource(...),
isActive:true,
friends: new kendo.data.DataSource(...),
selectionChanged: function(){...
}
});
$(document).ready(function () {
kendo.bind($("#sampleGridContainer"), viewModel);
});
In my .html file, I have a kendo grid:
<div id="sampleGridContainer">
<div data-role="grid"
data-columns="[...]"
data-editable="{ 'mode': 'popup', 'template': kendo.template($('#sampleTemplate').html()) }"
data-bind="source: people"></div>
</div>
<script id="sampleTemplate" type="text/x-kendo-template">
<form id="sampleForm">
...
<div data-container-for="somedropdown" class="k-edit-field">
<input name="somedropdown" id="somedropdown"
data-role="dropdownlist"
data-type="text"
data-text-field="name"
data-value-field="value"
data-bind="value: someValue, visible: isActive, source: friends, click: selectionChanged" />
</div>
...
</form>
</script>
Now, in my dropdown input element, someValue, isActive and friends variables are properly working - infact the drop down list shows up fine. But the problem is click event selectionChanged is not called. If I remove this from template, the event starts working, but my question is when all the other variables on the same scope are accessible in template, why does event selectionChanged not get called?
Any help is highly appreciated.
I have also encountered this problem, my workaround for this is that I initialize my kendoDropDownList on the edit event of grid.
edit: function (e){
e.container.find("input[name='somedropdown']").kendoDropDownList({
dataTextField: "name",
dataValueField: "value",
data-bind="value: viewModel.someValue, visible: viewModel.isActive, source: viewModel.friends, click: viewModel.selectionChanged"
});
}
Then the html would look something like this:
<div data-role="grid"
data-columns="[...]"
data-editable="{ 'mode': 'popup', 'template': kendo.template($('#sampleTemplate').html()) }"
data-bind="source: people, events: { edit: onEdit }">
</div>
<script id="sampleTemplate" type="text/x-kendo-template">
<form id="sampleForm">
<div data-container-for="somedropdown" class="k-edit-field">
<input name="somedropdown"/>
</div>
</form>
</script>
Hope this works for you.

Knockout-kendo KendoUI Grid Sorting by the input value in the grid cell

I have a KendoUI grid that is defined in my code using the Knockout-Kendo plugin as follow. It is important to note that this grids number of columns changes depending on the json received from the server.
<script type="text/html" id="grid">
<div class="grid-input input" data-bind="kendoGrid:
{
data: RowList,
columns: ko.toJS(GridHeader.ColumnDefinitionList),
rowTemplate: 'kendoui-grid-row',
altRowTemplate: 'kendoui-alt-grid-row',
useKOTemplates: true,
scrollable: false,
pageable: { pageSize: 10 },
sortable: true
}"></div>
</script>
<script type="text/html" id="kendoui-grid-row">
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }"></tr>
</script>
<script type="text/html" id="kendoui-alt-grid-row">
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }" class="k-alt"></tr>
</script>
<script type="text/html" id="grid-row">
<td><div class="grid-button delete-row-button"><span class="icon-delete"></span></div></td>
<!-- ko foreach: CellList -->
<td data-bind="template: { name: Input.Type, data: Input }">
</td>
<!-- /ko -->
</script>
<script type="text/html" id="text">
<input class="text-input input k-textbox" data-bind="value: Value" />
</script>
In this case, I have a grid filled with text boxes (in each cells of the grid, there is an input of type text). Now my problem is that sorting by clicking the grid headers does nothing even if there is texts in the inputs. What I would like to do is be able to define the target of the sorting. In this case it would be the value of the input inside the grid cells.
I've ran into a similar problem a while ago. The problem was that the Kendo Grid doesn't work well with ko observables. As a workaround you can create a computed which returns the data as a plain JS object:
this.RowList.asJS = ko.computed(function() {
return ko.toJS(this.RowList());
}, this);
Then change data: RowList with the following:
data: RowList.asJS
This however means you lose the observables in your row templates. A workaround for this is to get the original object again inside your row.
First create a helper function to quickly get an item by ID (assuming you have an Id property):
this.RowList.getById = function(id) {
return ko.utils.arrayFirst(this.RowList(), function(row) {
return ko.unwrap(row.Id) === id;
});
}, this);
Now you can call getById inside your row templates:
<script type="text/html" id="kendoui-grid-row">
<!-- ko with: $root.RowList.getById(Id) -->
<tr data-bind="visible: IsDeleted() == false, template: { name: 'grid-row' }"></tr>
<!-- /ko -->
</script>

Kendo control datepicker doesn't understand dateformat in MVVM

I have the following code:
<input data-role="datepicker" data-bind="value:referralData.Referral.from_date" />
With the value to bind as such:
from_date: "2014-01-01T00:00:00"
In the object and it doesn't bind anymore.
I have tried:
<input data-role="datepicker" data-bind="value:referralData.Referral.from_date, parseFormats:'YYYY-MM-DD\Thh:mm:ss'" />
But it states that: Uncaught Error: The parseFormats binding is not supported by the DatePicker widget. So I believe I have a syntax error that I am missing.
Does anyone know how to tell the datepicker to pick up this date?
data-bind is for live-binding options. If all you want to do is use the configuration option, you can use data-parse-formats:
<input data-role="datepicker"
data-parse-formats="YYYY-MM-DDThh:mm:ss"
data-bind="value:referralData.Referral.from_date" />
Also, if you want to use a 24 hour clock, you should use the this formatting config for time: HH:mm:ss
The solution by #Lars works, but the date format specifier is wrong (as of Kendo version 2014.3.119). It should be yyyy-MM-ddTHH:mm:ss (lower case for year and day and upper case for hour):
<input
data-role="datepicker"
data-bind="value:referralData.Referral.from_date"
data-parse-formats="yyyy-MM-ddTHH:mm:ss" />
And as a completion, if sometimes you need to, you can in fact pass more than one format, according to the documentation, like this:
<input
data-role="datepicker"
data-bind="value:referralData.Referral.from_date"
data-parse-formats="['yyyy-MM-ddTHH:mm:ss','yyyy-MM-dd']" />
You can create a custom binding for date format:
Custom Binding
kendo.data.binders.widget.dateFormat = kendo.data.Binder.extend({
init: function (widget, bindings, options) {
//call the base constructor
kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
},
refresh: function () {
var that = this,
value = that.bindings["dateFormat"].get(); //get the value from the View-Model
$(that.element).data("kendoDatePicker").setOptions({
format: value
}); //update the widget
}
});
HTML
<div id="report1" data-role="view" data-model="APP.models.report1">
<input data-role="datepicker" data-bind="value: start_date, dateFormat: date_format" />
</div>
Model
window.APP = {
models: {
report1: kendo.observable({
start_date: new Date(),
date_format: "dd/MM/yyyy",
}),
}
};
var app = new kendo.mobile.Application($(document.body), {
initial: "report1",
skin: "default",
});

Kendo mobile template styling/formatting not working

I am trying to use a template as shown below, the outcome is a view with all elements from the template on one line, even though i am using to separate the elements. Why does this not display properly? It seems that no matter what styling i do it still ends up a single line view.
UPDATE
The culprit is the kendo style sheet - kendo.mobile.all.min.css -
So the new question for a kendo expert is why does kendo handle input fields differently when they appear in a listview via a template than when they appear outside of a template?
An input field outside of a listview template gets this class
.km-ios .km-list input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="image"]):not([type="checkbox"]):not([type="radio"]):not(.k-input):not(.k-button), .km-ios .km-list select:not([multiple]), .km-ios .km-list .k-dropdown-wrap, .km-ios .km-list textarea
Which results in no odd styling rules :) Normal text field view
An input field inside of the template gets this class
.km-root input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="image"]):not([type="checkbox"]):not([type="radio"]):not(.k-input):not(.k-button), .km-root select:not([multiple]), .km-root .k-dropdown, .km-root textarea
which results in these rules being applied to it (making the field sit in a wierd spot and loose all normal field stlying ie border background etc.) Im not 100% sure which wrapper is causing this
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
font-size: 1.1rem;
color: #385487;
min-width: 6em;
border: 0;
padding: .4em;
outline: 0;
background:
transparent;
My work around is to give any text fields inside listview templates the class="k-input" which obviously excludes them from the above css -
<script src="kendo/js/jquery.min.js"></script>
<script src="kendo/js/kendo.mobile.min.js"></script>
<link href="kendo/styles/kendo.mobile.all.min.css" rel="stylesheet" />
<!-- eventDetail view -------------------------------------------------------------------------------------------------->
<div data-role="view" id="view-eventDetail" data-show="getEventDetailData" data-title="eventDetail">
<header data-role="header">
<div data-role="navbar">
<span data-role="view-title"></span>
<a data-align="right" data-role="button" class="nav-button" href="#view-myEvents">Back</a>
</div>
</header>
<form id="updateEventForm">
<div id="updateEvent">
<div id="eventDetail"></div>
<p>
<input type="button" id="eventUpdateCancelButton" style="width:30%" data-role="button" data-min="true" value="Back" />
<input type="submit" id="eventUpdateSaveButton" style="width:30%" data-role="button" data-min="true" value="Save" />
</p>
<div id="eventResult"></div>
</div>
</form>
</div>
<script id="eventDetail-template" type="text/x-kendo-template">
<p>
<input name="event_type" id="event_type" data-min="true" type="text" value="#= type #" />
</p>
<p>
<input name="event_loc" id="event_loc" data-min="true" type="text" value="#= type #" />
</p>
<p>
<input name="event_date_time" id="event_date_time" data-min="true" type="datetime" value="#= stamp #" />
</p>
<p>
Share this
<input data-role="switch" id="event_share" data-min="true" checked="checked" value="#= share #"/>
</p>
<input name="userID" id="userID" type="hidden" value="#= user_id #" />
<input name="eventID" id="eventID" type="hidden" value="#= event_id #" />
</script>
<script>
function getEventDetailData(e) {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "http://localhost/mpt/website/api/event_details.php",
dataType: "jsonp",
type: "GET",
data: { userID: e.view.params.user_id, eventID: e.view.params.event_id },
cache: false
},
parameterMap: function(options) {
return {
userID: options.userID,
eventID: options.eventID
};
}
},
schema: { // describe the result format
data: "results" // the data which the data source will be bound to is in the "results" field
}
});
console.log(e);
$("#eventDetail").kendoMobileListView({
dataSource: dataSource,
template: kendo.template($("#eventDetail-template").html())
}).data("kendoMobileListView");
}
//update event
function sendUpdateEvent() {
var siteURI = "http://localhost/mpt/website/api/update_event.php?";
app.showLoading();
var user_id = $('#userID').val();
var event_id = $('#eventID').val();
var event_type = $('#event_type').val();
var event_loc = $('#event_loc').val();
var event_date_time = $('#event_date_time').val();
var event_share = $('#event_share').val();
var formVals = 'eventID=' + event_id + '&userID=' + user_id + '&event_type=' + event_type + '&event_loc=' + event_loc + '&event_date_time=' + event_date_time + '&event_share=' + event_share;
var fullURI = siteURI + formVals;
$.ajax({
url: fullURI, dataType: 'json', success: function (data) {
$('#eventResult').html(data.results);
app.hideLoading();
app.navigate("#view-myEvents");
}
});
}
$('#eventUpdateCancelButton').click(function () {
app.navigate("#view-myEvents");
});
$('#eventUpdateSaveButton').click(function () {
sendUpdateEvent();
});
$('#updateEventForm').submit(function () {
sendUpdateEvent();
return false;
});
</script>
ListView widgets are supposed to be applied to <ul> elements.
Try changing:
<div id="eventDetail"></div>
to:
<ul id="eventDetail"></ul>
Also with this bit of code:
$("#eventDetail").kendoMobileListView({
dataSource: dataSource,
template: kendo.template($("#eventDetail-template").html())
}).data("kendoMobileListView");
The .data() call on the end isn't doing anything here and can be removed, and also you can pass just the text string as the template. You don't need to call kendo.template() yourself. So you can change that to just:
$("#eventDetail").kendoMobileListView({
dataSource: dataSource,
template: $("#eventDetail-template").html()
});

Resources