I am using the MVC extensions to try and accomplish what I am trying to do here. I have been trying to get the Scheduler custom editor to work. I have followed the example provided in the link ?? But still when I call double click the scheduler instead of giving me my custom template it just provides all the properties of the model on a pop-up window. I have included here the method from the controller , as well as my view and the template I am trying to implement,along with the viewmodel being used. I have also provided screen shots of the directory structure and the pop-up. I have not yet created the Appointments_Create, Appointments_Update or Appointments_Destory at this time because I just wanted the pop-up to load correctly.
//*********************************
//* Controller Method *
//*********************************
[Authorize(Roles = "Customer")] // need to add client role also
public virtual JsonResult Appointments_Read([DataSourceRequest] DataSourceRequest request)
{
var sbasUser = new SBASUser();
var user = sbasUser.GetSBASUserByEmail(User.Identity.GetUserName());
var appointments = new Appointment().GetAllCustomerAppointments(user.UserId);
var t = appointments.ToList().Select(m => new AppointmentModel
{
AppointmentId = m.AppointmentId,
Title = m.Title,
Start = m.Start,
End = m.End,
StartTimezone = m.StartTimezone,
EndTimezone = m.EndTimezone,
Description = m.Description,
IsAllDay = m.IsAllDay,
RecurrenceID = m.RecurrenceId,
RecurrenceException = m.RecurrenceException,
RecurrenceRule = m.RecurrenceRule,
AddressId = m.AddressId,
CustomerId = m.CustomerId,
ClientId = m.ClientId,
ServiceTypeId = m.ServiceTypeId
}).AsQueryable();
return Json(t.ToDataSourceResult(request));
}
//*********************************
//* Index.cshtml *
//*********************************
@{
Layout = "~/Views/Shared/_CustomerLoggedInLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<h1>Appointments Calendar</h1>
</div>
</div>
@{
var startdate = DateTime.Now;
}
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="btn btn-primary" >Submit</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="row">
<div class="col-lg-12">
@(Html.Kendo().Scheduler<SBAS_Web.Models.AppointmentModel>()
.Name("scheduler")
.Date(new DateTime(startdate.Year, startdate.Month, startdate.Day))
.StartTime(new DateTime(startdate.Year, startdate.Month, startdate.Day, 8, 00, 00))
.Height(500)
.Views(views =>
{
views.DayView(dayView=>dayView.Selected(true));
views.WeekView();
views.MonthView();
})
.Editable(editable => editable.TemplateName("CustomEditorTemplate"))
.Timezone("Etc/UTC")
.DataSource(d => d
.Model(m =>
{
m.Id(f => f.AppointmentId);
m.Field(f => f.Title).DefaultValue("No title");
m.RecurrenceId(f => f.RecurrenceID);
})
.Events(e => e.Error("error_handler"))
.Read("Appointments_Read", "Appointment")
)
)
</div>
</div>
<div id="map_canvas">
</div>
<script type="text/javascript">
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
alert(message);
var scheduler = $("#scheduler").data("kendoScheduler");
scheduler.one("dataBinding", function(e) {
//prevent saving if server error is thrown
e.preventDefault();
});
}
}
</script>
//*********************************
//* AppointmentModel class *
//*********************************
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Kendo.Mvc.UI;
using SBAS_Core.Common.Attributes;
namespace SBAS_Web.Models
{
public class AppointmentModel : ISchedulerEvent
{
private DateTime _start;
private DateTime _end;
public long AppointmentId { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
[Required]
public DateTime Start
{ get { return _start; }
set { _start = value.ToUniversalTime(); }
}
[Required]
[DateGreaterThan(OtherField = "Start")]
public DateTime End
{ get { return _end; }
set { _end = value.ToUniversalTime(); }
}
public bool IsAllDay { get; set; }
public string RecurrenceRule { get; set; }
public int? RecurrenceID { get; set; }
public string RecurrenceException { get; set; }
public string StartTimezone { get; set; }
public string EndTimezone { get; set; }
public long CustomerId { get; set; }
public long ClientId { get; set; }
public bool UseClientAddress { get; set; }
public long? AddressId { get; set; }
//For type of service this appointment is for
public long ServiceTypeId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public long SelectedCityId { get; set; }
public long SelectedStateId { get; set; }
[Display(Name = "City")]
public SelectList CityList { get; set; }
[Display(Name = "State")]
public SelectList StateList { get; set; }
public string ZipCode { get; set; }
public decimal? Longitude { get; set; }
public decimal? Latitude { get; set; }
}
}
//***********************************
//* CustomEditorTemplate.cshtml *
//***********************************
@model SBAS_Web.Models.AppointmentModel
@{
//required in order to render validation attributes
ViewContext.FormContext = new FormContext();
}
@functions{
public Dictionary<string, object> generateDatePickerAttributes(
string elementId,
string fieldName,
string dataBindAttribute,
Dictionary<string, object> additionalAttributes = null)
{
Dictionary<string, object> datePickerAttributes = additionalAttributes != null ? new Dictionary<string, object>(additionalAttributes) : new Dictionary<string, object>();
datePickerAttributes["id"] = elementId;
datePickerAttributes["name"] = fieldName;
datePickerAttributes["data-bind"] = dataBindAttribute;
datePickerAttributes["required"] = "required";
datePickerAttributes["style"] = "z-index: inherit;";
return datePickerAttributes;
}
}
<div class="k-edit-label">
@(Html.LabelFor(model => model.Title))
</div>
<div data-container-for="title" class="k-edit-field">
@(Html.TextBoxFor(model => model.Title, new { @class = "k-textbox", data_bind = "value:title" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.Start))
</div>
<div data-container-for="start" class="k-edit-field">
@(Html.Kendo().DateTimePickerFor(model => model.Start)
.HtmlAttributes(generateDatePickerAttributes("startDateTime", "start", "value:start,invisible:isAllDay")))
@(Html.Kendo().DatePickerFor(model => model.Start)
.HtmlAttributes(generateDatePickerAttributes("startDate", "start", "value:start,visible:isAllDay")))
<span data-bind="text: startTimezone"></span>
<span data-for="start" class="k-invalid-msg"></span>
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.End))
</div>
<div data-container-for="end" class="k-edit-field">
@(Html.Kendo().DateTimePickerFor(model => model.End)
.HtmlAttributes(generateDatePickerAttributes(
"endDateTime",
"end",
"value:end,invisible:isAllDay",
new Dictionary<string, object>() {{"data-dateCompare-msg", "End date should be greater than or equal to the start date"}})))
@(Html.Kendo().DatePickerFor(model => model.End)
.HtmlAttributes(generateDatePickerAttributes(
"endDate",
"end",
"value:end,visible:isAllDay",
new Dictionary<string, object>() {{"data-dateCompare-msg", "End date should be greater than or equal to the start date"}})))
<span data-bind="text: endTimezone"></span>
<span data-for="end" class="k-invalid-msg"></span>
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.IsAllDay))
</div>
<div data-container-for="isAllDay" class="k-edit-field">
<input data-bind="checked: isAllDay" data-val="true" id="IsAllDay" name="IsAllDay" type="checkbox" />
</div>
<div class="endTimezoneRow">
<div class="k-edit-label"></div>
<div class="k-edit-field">
<label class="k-check">
<input checked="checked" class="k-timezone-toggle" type="checkbox" value="true" />
Use separate start and end time zones
</label>
</div>
</div>
<script>
$(".k-timezone-toggle").on("click", function () {
var isVisible = $(this).is(":checked");
var container = $(this).closest(".k-popup-edit-form");
var endTimezoneRow = container.find("label[for='EndTimezone']").parent().add(container.find("div[data-container-for='endTimezone']"));
endTimezoneRow.toggle(isVisible);
if (!isVisible) {
var uid = container.attr("data-uid");
var scheduler = $("\#scheduler").data("kendoScheduler");
var model = scheduler.dataSource.getByUid(uid);
model.set("endTimezone", null);
}
});
var endTimezone = '${data.endTimezone}';
if (!endTimezone || endTimezone == "null") {
$(".k-timezone-toggle").trigger('click');
}
</script>
<div class="k-edit-label">
@(Html.LabelFor(model => model.StartTimezone))
</div>
<div data-container-for="startTimezone" class="k-edit-field">
@(Html.Kendo().TimezoneEditorFor(model => model.StartTimezone)
.HtmlAttributes(new { data_bind = "value:startTimezone" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.EndTimezone))
</div>
<div data-container-for="endTimezone" class="k-edit-field">
@(Html.Kendo().TimezoneEditorFor(model => model.EndTimezone)
.HtmlAttributes(new { data_bind = "value:endTimezone" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.RecurrenceRule))
</div>
<div data-container-for="recurrenceRule" class="k-edit-field">
@(Html.Kendo().RecurrenceEditorFor(model => model.RecurrenceRule)
.HtmlAttributes(new { data_bind = "value:recurrenceRule" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.Description))
</div>
<div data-container-for="description" class="k-edit-field">
@(Html.TextAreaFor(model => model.Description, new { @class = "k-textbox", data_bind = "value:description" }))
</div>
@{
ViewContext.FormContext = null;
}
//*********************************
//* Controller Method *
//*********************************
[Authorize(Roles = "Customer")] // need to add client role also
public virtual JsonResult Appointments_Read([DataSourceRequest] DataSourceRequest request)
{
var sbasUser = new SBASUser();
var user = sbasUser.GetSBASUserByEmail(User.Identity.GetUserName());
var appointments = new Appointment().GetAllCustomerAppointments(user.UserId);
var t = appointments.ToList().Select(m => new AppointmentModel
{
AppointmentId = m.AppointmentId,
Title = m.Title,
Start = m.Start,
End = m.End,
StartTimezone = m.StartTimezone,
EndTimezone = m.EndTimezone,
Description = m.Description,
IsAllDay = m.IsAllDay,
RecurrenceID = m.RecurrenceId,
RecurrenceException = m.RecurrenceException,
RecurrenceRule = m.RecurrenceRule,
AddressId = m.AddressId,
CustomerId = m.CustomerId,
ClientId = m.ClientId,
ServiceTypeId = m.ServiceTypeId
}).AsQueryable();
return Json(t.ToDataSourceResult(request));
}
//*********************************
//* Index.cshtml *
//*********************************
@{
Layout = "~/Views/Shared/_CustomerLoggedInLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<h1>Appointments Calendar</h1>
</div>
</div>
@{
var startdate = DateTime.Now;
}
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="btn btn-primary" >Submit</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="row">
<div class="col-lg-12">
@(Html.Kendo().Scheduler<SBAS_Web.Models.AppointmentModel>()
.Name("scheduler")
.Date(new DateTime(startdate.Year, startdate.Month, startdate.Day))
.StartTime(new DateTime(startdate.Year, startdate.Month, startdate.Day, 8, 00, 00))
.Height(500)
.Views(views =>
{
views.DayView(dayView=>dayView.Selected(true));
views.WeekView();
views.MonthView();
})
.Editable(editable => editable.TemplateName("CustomEditorTemplate"))
.Timezone("Etc/UTC")
.DataSource(d => d
.Model(m =>
{
m.Id(f => f.AppointmentId);
m.Field(f => f.Title).DefaultValue("No title");
m.RecurrenceId(f => f.RecurrenceID);
})
.Events(e => e.Error("error_handler"))
.Read("Appointments_Read", "Appointment")
)
)
</div>
</div>
<div id="map_canvas">
</div>
<script type="text/javascript">
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
alert(message);
var scheduler = $("#scheduler").data("kendoScheduler");
scheduler.one("dataBinding", function(e) {
//prevent saving if server error is thrown
e.preventDefault();
});
}
}
</script>
//*********************************
//* AppointmentModel class *
//*********************************
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Kendo.Mvc.UI;
using SBAS_Core.Common.Attributes;
namespace SBAS_Web.Models
{
public class AppointmentModel : ISchedulerEvent
{
private DateTime _start;
private DateTime _end;
public long AppointmentId { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
[Required]
public DateTime Start
{ get { return _start; }
set { _start = value.ToUniversalTime(); }
}
[Required]
[DateGreaterThan(OtherField = "Start")]
public DateTime End
{ get { return _end; }
set { _end = value.ToUniversalTime(); }
}
public bool IsAllDay { get; set; }
public string RecurrenceRule { get; set; }
public int? RecurrenceID { get; set; }
public string RecurrenceException { get; set; }
public string StartTimezone { get; set; }
public string EndTimezone { get; set; }
public long CustomerId { get; set; }
public long ClientId { get; set; }
public bool UseClientAddress { get; set; }
public long? AddressId { get; set; }
//For type of service this appointment is for
public long ServiceTypeId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public long SelectedCityId { get; set; }
public long SelectedStateId { get; set; }
[Display(Name = "City")]
public SelectList CityList { get; set; }
[Display(Name = "State")]
public SelectList StateList { get; set; }
public string ZipCode { get; set; }
public decimal? Longitude { get; set; }
public decimal? Latitude { get; set; }
}
}
//***********************************
//* CustomEditorTemplate.cshtml *
//***********************************
@model SBAS_Web.Models.AppointmentModel
@{
//required in order to render validation attributes
ViewContext.FormContext = new FormContext();
}
@functions{
public Dictionary<string, object> generateDatePickerAttributes(
string elementId,
string fieldName,
string dataBindAttribute,
Dictionary<string, object> additionalAttributes = null)
{
Dictionary<string, object> datePickerAttributes = additionalAttributes != null ? new Dictionary<string, object>(additionalAttributes) : new Dictionary<string, object>();
datePickerAttributes["id"] = elementId;
datePickerAttributes["name"] = fieldName;
datePickerAttributes["data-bind"] = dataBindAttribute;
datePickerAttributes["required"] = "required";
datePickerAttributes["style"] = "z-index: inherit;";
return datePickerAttributes;
}
}
<div class="k-edit-label">
@(Html.LabelFor(model => model.Title))
</div>
<div data-container-for="title" class="k-edit-field">
@(Html.TextBoxFor(model => model.Title, new { @class = "k-textbox", data_bind = "value:title" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.Start))
</div>
<div data-container-for="start" class="k-edit-field">
@(Html.Kendo().DateTimePickerFor(model => model.Start)
.HtmlAttributes(generateDatePickerAttributes("startDateTime", "start", "value:start,invisible:isAllDay")))
@(Html.Kendo().DatePickerFor(model => model.Start)
.HtmlAttributes(generateDatePickerAttributes("startDate", "start", "value:start,visible:isAllDay")))
<span data-bind="text: startTimezone"></span>
<span data-for="start" class="k-invalid-msg"></span>
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.End))
</div>
<div data-container-for="end" class="k-edit-field">
@(Html.Kendo().DateTimePickerFor(model => model.End)
.HtmlAttributes(generateDatePickerAttributes(
"endDateTime",
"end",
"value:end,invisible:isAllDay",
new Dictionary<string, object>() {{"data-dateCompare-msg", "End date should be greater than or equal to the start date"}})))
@(Html.Kendo().DatePickerFor(model => model.End)
.HtmlAttributes(generateDatePickerAttributes(
"endDate",
"end",
"value:end,visible:isAllDay",
new Dictionary<string, object>() {{"data-dateCompare-msg", "End date should be greater than or equal to the start date"}})))
<span data-bind="text: endTimezone"></span>
<span data-for="end" class="k-invalid-msg"></span>
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.IsAllDay))
</div>
<div data-container-for="isAllDay" class="k-edit-field">
<input data-bind="checked: isAllDay" data-val="true" id="IsAllDay" name="IsAllDay" type="checkbox" />
</div>
<div class="endTimezoneRow">
<div class="k-edit-label"></div>
<div class="k-edit-field">
<label class="k-check">
<input checked="checked" class="k-timezone-toggle" type="checkbox" value="true" />
Use separate start and end time zones
</label>
</div>
</div>
<script>
$(".k-timezone-toggle").on("click", function () {
var isVisible = $(this).is(":checked");
var container = $(this).closest(".k-popup-edit-form");
var endTimezoneRow = container.find("label[for='EndTimezone']").parent().add(container.find("div[data-container-for='endTimezone']"));
endTimezoneRow.toggle(isVisible);
if (!isVisible) {
var uid = container.attr("data-uid");
var scheduler = $("\#scheduler").data("kendoScheduler");
var model = scheduler.dataSource.getByUid(uid);
model.set("endTimezone", null);
}
});
var endTimezone = '${data.endTimezone}';
if (!endTimezone || endTimezone == "null") {
$(".k-timezone-toggle").trigger('click');
}
</script>
<div class="k-edit-label">
@(Html.LabelFor(model => model.StartTimezone))
</div>
<div data-container-for="startTimezone" class="k-edit-field">
@(Html.Kendo().TimezoneEditorFor(model => model.StartTimezone)
.HtmlAttributes(new { data_bind = "value:startTimezone" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.EndTimezone))
</div>
<div data-container-for="endTimezone" class="k-edit-field">
@(Html.Kendo().TimezoneEditorFor(model => model.EndTimezone)
.HtmlAttributes(new { data_bind = "value:endTimezone" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.RecurrenceRule))
</div>
<div data-container-for="recurrenceRule" class="k-edit-field">
@(Html.Kendo().RecurrenceEditorFor(model => model.RecurrenceRule)
.HtmlAttributes(new { data_bind = "value:recurrenceRule" }))
</div>
<div class="k-edit-label">
@(Html.LabelFor(model => model.Description))
</div>
<div data-container-for="description" class="k-edit-field">
@(Html.TextAreaFor(model => model.Description, new { @class = "k-textbox", data_bind = "value:description" }))
</div>
@{
ViewContext.FormContext = null;
}