This is a migrated thread and some comments may be shown as answers.

Custom Editor minor issues and 1 major calendar issue

7 Answers 249 Views
Scheduler
This is a migrated thread and some comments may be shown as answers.
Chris
Top achievements
Rank 1
Chris asked on 07 Mar 2015, 06:50 AM
Continuing my evaluation, after finding this project:
http://www.telerik.com/support/code-library/custom-editor-9fd60fca3c02

most of my questions from the previous thread about customizing the scheduler were answered. Building off the above example I have run into a few problems.

1. While the custom editor will allow me to save events to the database, the calendar will not display these events.
@(Html.Kendo().Scheduler<SchedulerViewModel>()
        .Name("scheduler")
        .Date(new DateTime(2015, 2, 1))
        .StartTime(new DateTime(2015, 2, 1, 7, 00, 00))
        .Height(600)
        .Timezone("Etc/UTC")
        .Views(views =>
            {
                views.DayView();
                views.WeekView();
                views.MonthView(monthView => monthView.Selected(true));
            })
        .DataSource(d => d.Model(m =>
            {
                m.Id(f => f.EventId);
                m.Field(f => f.Title).DefaultValue("No title");
                m.RecurrenceId(f => f.RecurrenceID);
                m.Field(f => f.IsAllDay).DefaultValue(false);
            })
            .Read("Read", "Scheduler")
            .Create("Create", "Scheduler")
            .Destroy("Destroy", "Scheduler")
            .Update("Update", "Scheduler")
 
        )
        .Editable(editable =>
            {
                editable.TemplateName("CustomEditorTemplate");
            })
    )
It appears to be pulling and pushing the data just fine using a clone of the the ScheduleTaskService from the demo solution, just not displaying for whatever reason.

2. After clicking save on the CustomEditorTemplate the pop-up is not closing as it does with the standard editor.

The rest of the issues are really about specific components in the CustomEditorTemplate but rather than splash all over the forums figured I would list them here.

3. DropDownList component -- is there a way to set a default/selected value. I found in my testing that if I did not change the value of the ddl it returned a null on submit.

4. MultiSelect component -- is there a way to set a ":water mark" or a "click me" a "down arrow" rather than a blank box. After you use it once it is intuitive but the first time I saw it, I thought the list didn't load.

5. DateTimePicker component -- is there a way to set the default time to something other than 12:00 AM?

6.  In the CustomEditorTemplate by default it isAllDayEvent is set to true. How on earth do you change that? I tried setting the value to false, the data-val to false, and scripting I attempted broke the form so I am at a loss.

@model PokerLeagueMVCv2.Models.SchedulerViewModel
            
@{
    //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="VenueId" class="k-edit-field">
 
    @(Html.Kendo().DropDownListFor(model => model.VenueId)
            .Name("Venue")
            .HtmlAttributes(new { data_bind = "value:VenueId", style = "width: 300px" })
            .DataTextField("VenueName")
            .DataValueField("VenueId")
            .DataSource(source =>
            {
                source.Read(read => { read.Action("VenueDropDownList", "DropDownList"); });
            })
 
    )
 
    </div>
 
<div class="k-edit-label">
    @(Html.LabelFor(model => model.RegionIds))
</div>
<div data-container-for="RegionIds" class="k-edit-field">
 
    @(Html.Kendo().MultiSelectFor(model => model.RegionIds)
            .Name("AssignRegions")
            .HtmlAttributes(new { data_bind = "value:RegionIds", style = "width: 200px" })
            .DataTextField("RegionName")
            .DataValueField("RegionId")
            .DataSource(source =>
            {
                source.Read(read => { read.Action("RegionDropDownList", "DropDownList"); });
            })
 
    )
</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 id="IsAllDay" data-bind="checked: isAllDay" data-val="false" 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>
    <div class="k-edit-label">
        @(Html.LabelFor(model => model.Registration))
    </div>
    <div data-container-for="Registration" class="k-edit-field">
        <input data-bind="checked: Registration" data-val="false" id="Registration" name="Registration" type="checkbox" class="k-registration-toggle" />
    </div>
     
    <div class="k-edit-label">
        @(Html.LabelFor(model => model.MaxRegistrations))
    </div>
    <div data-container-for="MaxRegistrations" class="k-edit-field">
        @(Html.TextBoxFor(model => model.MaxRegistrations, new { @class = "k-textbox", data_bind = "value:MaxRegistrations" }))
    </div>
    <div class="k-edit-label">
        @(Html.LabelFor(model => model.MaxWaitList))
    </div>
    <div data-container-for="MaxWaitList" class="k-edit-field">
        @(Html.TextBoxFor(model => model.MaxWaitList, new { @class = "k-textbox", data_bind = "value:MaxWaitList" }))
    </div>
    <div class="k-edit-label">
        @(Html.LabelFor(model => model.MaxWinsAllowed))
    </div>
    <div data-container-for="MaxWinsAllowed" class="k-edit-field">
        @(Html.TextBoxFor(model => model.MaxWinsAllowed, new { @class = "k-textbox", data_bind = "value:MaxWinsAllowed" }))
    </div>
 
    @{
        ViewContext.FormContext = null;
    }

Here is the ViewModel:
public class SchedulerViewModel: ISchedulerEvent
    {
        public string Title { get; set; }
        private DateTime start;
        public DateTime Start
        {
            get
            {
                return start;
            }
            set
            {
                start = value.ToUniversalTime();
            }
        }
        private DateTime end;
        public DateTime End
        {
            get
            {
                return end;
            }
            set
            {
                end = value.ToUniversalTime();
            }
        }
        [DisplayName("Start Timezone")]
        public string StartTimezone { get; set; }
        [DisplayName("End Timezone")]
        public string EndTimezone { get; set; }
        public string Description { get; set; }
        public bool IsAllDay { get; set; }
        public string Recurrence { get; set; }
        public int? RecurrenceID { get; set; }
        [DisplayName("Recurrence")]
        public string RecurrenceRule { get; set; }
        public string RecurrenceException { get; set; }
 
        //this is for charity events or session main events
        public bool Registration { get; set; }
        [DisplayName("Max Reg")]
        public int MaxRegistrations { get; set; }
        [DisplayName("Max Wins")]
        public int MaxWinsAllowed { get; set; }
        [DisplayName("Max Wait")]
        public int MaxWaitList { get; set; }
 
        //IDs
        public int VenueId { get; set; }
        public int EventId { get; set; }
        [DisplayName("Regions")]
        public ICollection<Region> RegionIds { get; set; }
 
        public LeagueEvent ToEntity()
        {
            return new LeagueEvent
            {
                EventId = EventId,
                VenueId =VenueId,
                Start = Start,
                End = End,
                StartTimezone = StartTimezone,
                EndTimezone = EndTimezone,
                Description = Description,
                IsAllDay = IsAllDay,
                Recurrence = Recurrence,
                RecurrenceID = RecurrenceID,
                RecurrenceRule = RecurrenceRule,
                RecurrenceException = RecurrenceException,
                Registration = Registration,
                MaxRegistrations = MaxRegistrations,
                MaxWinsAllowed = MaxWinsAllowed,
                MaxWaitList = MaxWaitList,
                RegionIds = RegionIds
            };
 
        }
    }




Any help or guidance you can provide would be greatly appreciated.

Thanks,
Chris

7 Answers, 1 is accepted

Sort by
0
Chris
Top achievements
Rank 1
answered on 08 Mar 2015, 09:55 PM
I have a lead on what the issue is with the events not displaying on the calendar. It seems to be centered around timezones causing problems.  

The EF class had :
public DateTime Start { get; set; }
public DateTime End { get; set; }

The View Model had:

private DateTime start;
public DateTime Start
{
    get
    {
        return start;
    }
    set
    {
        start = value.ToUniversalTime();
    }
}
private DateTime end;
public DateTime End
{
    get
    {
        return end;
    }
    set
    {
        end = value.ToUniversalTime();
    }
}
The scheduler has .Timezone() set to Eastern Standard

I would create an event. I would set the timezone during creation to Eastern. It would insert the time as UTC and store it.  However, when I pulled the record back out something would happen and inspecting the event object would show that the event had the same start and end times basically nullifying the event. (and no I did not duplicate one of the times)

Step 1 : stopped using the timezone component on the event editor. Result data still be stored UTC and not displaying on calendar. 
Step 2 : removed timezone from scheduler. Result data displayed on calendar in UTC times
Step 3 : remove UTC conversion from view model. Displays correctly on calendar stores as the selected values.

I need to understand what is going on with these timezone issues and get them resolved because it is a requirement for the eval on the scheduler tool.

As usual any help would be appreciated.

Thanks,
Chris

0
Chris
Top achievements
Rank 1
answered on 09 Mar 2015, 09:31 PM
Update....
Test 1:
No .timezone() property on calendar.

Test Entry:
Title: 87 Pour House
Regions : CFL
Start: 3/13/2015 6:00 PM
End: 3/13/2015 10:00 PM
Starttimezone : America/New_York
RecurrenceRule:FREQ=WEEKLY;BYDAY=FR

Observations:
1. Again the edit form would not close after the record was entered. However, the record was inserted into the db. 
2. After some research it seems that best practices is to store datetimes as utc. Made changes it the insert converting to utc, rather than the view model. Data stored correctly.
3. The event did not appear on the calendar even after refresh.
4. Deleted the many-to-many record relation between events and regions. Refreshed the calendar and the event appeared. For whatever reason this seems to be the issue with events not appearing on the calendar and I would bet also why the editor is not closing on submit.
5. While the event is now showing on the calendar it is showing in UTC time even though the record has a timezone assoicated with it which I had assumed was for conversion to correct timezone.

Test 2:
.timezone() property on calendar set to "EST".

Test Entry:
Title: 87 Pour House
Regions : No Region Selected
Start: 3/13/2015 6:00 PM
End: 3/13/2015 10:00 PM
Starttimezone : America/New_York
RecurrenceRule:FREQ=WEEKLY;BYDAY=FR

Observations:
1. Observation 4 from test 1 was correct. Not assigning a region the event closed on submit without issue.
2. Initally the event shows correctly on the calendar. However upon refresh again it posts in UTC time.

Test 3:
No .timezone() property on calendar.

Test Entry:
Title: 87 Pour House
Regions : No Region Selected
Start: 3/13/2015 6:00 PM
End: 3/13/2015 10:00 PM
Starttimezone : No Timezone selected
RecurrenceRule:FREQ=WEEKLY;BYDAY=FR

Observations:
1. Same as test 3 observation 2. Initally the event shows correctly on the calendar. However upon refresh again it posts in UTC time.

Test 4:
No .timezone() property on calendar.

Test Entry:
Title: 87 Pour House
Regions : No Region Selected
Start: 3/13/2015 6:00 PM
End: 3/13/2015 10:00 PM
Starttimezone : America/New_York
RecurrenceRule:FREQ=WEEKLY;BYDAY=FR

Observations:
1. Added the following code block in the getall method and the result was successful display of event. Correct time based upon either the event timezone or the browsertimezone:
public SchedulerViewModel HandleTimezones(SchedulerViewModel e)
        {
            TimeZoneInfoHelper tziHelper = new TimeZoneInfoHelper();
            if (!string.IsNullOrEmpty(e.StartTimezone) && string.IsNullOrEmpty(e.EndTimezone))
            {
                 
                TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
                e.Start = DateTime.SpecifyKind(e.Start, DateTimeKind.Utc);
                e.End = DateTime.SpecifyKind(e.End, DateTimeKind.Utc);
                e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tzi);
                e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tzi);
            }
            if (!string.IsNullOrEmpty(e.StartTimezone) && !string.IsNullOrEmpty(e.EndTimezone))
            {
                TimeZoneInfo tziStart = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
                TimeZoneInfo tziEnd = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.EndTimezone));
                e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tziStart);
                e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tziEnd);
            }
            return e;
        }
So it seems to be working correctly. Now on to figure out why a multi select is crashing the calendar.




0
Chris
Top achievements
Rank 1
answered on 10 Mar 2015, 01:15 PM
I posted consolidated code without testing. You actually need a HandleToUTC and a HandleFromUTC depending on whether you are pushing or pulling records from the db. The pattern is the same for both with the toUTC have a kind value of unspecified and the FromUTC having the timezone value.
0
Vladimir Iliev
Telerik team
answered on 11 Mar 2015, 07:41 AM
Hello Chris,

I would like to remind you that as a general practice it is accepted to ask different questions in separate support threads / forum posts. In this way it is much easier to follow and concentrate on the particular issue which usually leads to its faster resolving.

Please find the answers of your questions below:

1) From the provided information it's not clear for us what is the exact reason for the events not being renderd after creation. You mention that deleting the "Regions" property did the trick, however if there are no circular references you should be able to use complex properties in the Scheduler model. If you still experience this issue and you need the complex field on the client side please provide runable example where the issue is reproduced for further investigation. 

2) The editor of the Scheduler would not be closed in cases when the server returns either HTTP error, there is "Errors" field in the response or the response from the server cannot be parsed.

3) You can set default value for given field in the Scheduler DataSource:
.DataSource(d => d
    .Model(m => {
        m.Id(f => f.MeetingID);
        m.Field(f => f.Title).DefaultValue("No title");
        m.RecurrenceId(f => f.RecurrenceID);
        m.Field(f => f.RoomID).DefaultValue(1);
    })

Another option is to set the "OptionLabel" option of the DropDownList editor which is equal to "null" value.

4) You can use the "Placeholder" option of the MultiSelect: 5) The DatePickers which are bind to "Start" / "End" fields are always set to the current slot start/end times where the user is clicked to create the event. Possible solution is to use the "Edit" event of the Scheduler to modify these values. 

6) The "IsAllDay" property is handled the same way as the above fields - it's set to the value of the current slot. You can change that either by defining DefaultValue for this field or by using the "Edit" event of the Scheduler.

Also please note that the Scheduler accepts and sends back to the server only UTC dates - that why you should set the DateTime kind inside the model as shown in the target demo. 

Regards,
Vladimir Iliev
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Chris
Top achievements
Rank 1
answered on 11 Mar 2015, 06:13 PM
Hello Vladimir,

Thank you for response. I apologize for the general listing but I figure these were simple and quick issues resulting more from my lack of familiarity with the tool set than actual coding issues and I didn't want to spam the forum with a ton of simplistic issues.

Issues 1 & 2 were broken out into a separate post and I was able to resolve them once I realized where the issue was stemming from. However, it turns out in addressing your UTC comment for testing while it is working using resources and the standard scheduler/editor it is not working in the custom editor. I shall post an update in the thread "Multiple Resource Issues" in this forum.

3. That is a great tip for the datasouce and I ended up using the OptionLabel for the ddl. I either missed seeing it on my first attempts or it didn't click with me that was where to set the default.

4. Thanks will implement that.

5. I will look into the edit event about setting the default times. The reason for this is most of our events are same day events and usually occur in the evening. In my testing it got tedious for me to keep scrolling for times and having to click the enddate to the same date. If it is tedious for me in testing it will be unbearable to the people that use it.

6. I think that it will have to happen in the edit event as well. I just tested the default values approach and while converting the checkbox to a kendo checkbox and setting the value to false does work it breaks the javascript functionality. Adding the data-bind = "checked: isAllDay" as an htmlattributes does fix the functionality but still shows up as checked on load and the datetime pickers are set to just day.


Concerning the UTC dates comments. In the example you use the value.ToUniversalTime(); for your 'sets' in the model  which will work fine as long your server is in the same time zone as the person creating the event. I believe  this is because the submit to the server pushes up the selected datetime kind of "local" and .ToUniversalTime() references localtime system time when it converts to UTC. Also, I found that with and without timezone the scheduler does not convert back from utc to local browser in the getall(). It will however if you have set a timezone account for daylight savings. At least this is what I am observing with the attached screen shots. That is why I put in an agnostic timeconverter with timezone being required. If I am doing something wrong or misunderstood please enlighten me, time is a wibbly wobbly timey whimey thing that I don't really understand.

Again, thanks for your detailed response and I will look to implement your suggestions and in the future will try to break out the issues to one per thread.

Chris

p.s. On a side note is there a way to edit a post. The batteries were dying in my keyboard and in my original post  "Multiple Resource Issues"  I accidently inserted a huge amount of white space that I would like to remove.

0
Vladimir Iliev
Telerik team
answered on 13 Mar 2015, 08:46 AM
Hello Chris,


Basically the Scheduler dataSource expects from the server and sends back only UTC dates - that why it's required to call the "ToUniversalTime" method in order to set the kind of the date correctly. Also I would suggest to set explicitly "Timezone" option of the Scheduler in order to convert the dates from UTC to the correct timezone. For more information about how to setup the Scheduler correctly you can check the following help article in our documentation:

Regards,
Vladimir Iliev
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Chris
Top achievements
Rank 1
answered on 13 Mar 2015, 04:40 PM
Hello Vladimir,

I must have missed this code in the demo task_read():

//Specify the DateTimeKind to be UTC
            Start = DateTime.SpecifyKind(task.Start, DateTimeKind.Utc),
            End = DateTime.SpecifyKind(task.End, DateTimeKind.Utc),

I am sure that the scheduler does detect local timezone and convert referencing the timezone field if there is one. So I was basically doing what the scheduler was already going to do once it had a kind value from the get side of things.

However, I am still not convinced on the submit side that .ToUniversalTime(); is the way to go since it references local server time and the datetime object being passed in also shows as "local".  I have a server in a different timezone that I can test against for my own edification as this is getting off topic.

Thank you for your time in helping me understand this.

Chris


Tags
Scheduler
Asked by
Chris
Top achievements
Rank 1
Answers by
Chris
Top achievements
Rank 1
Vladimir Iliev
Telerik team
Share this question
or