Good day,
I am using the ASP.NET MVC server side scheduler. What is noticeably missing is a way, when one chooses to delete/edit an entire series of a recurring event, to specify
1. Delete this entire series, or
2. Delete the highlighted event and all future events in the series, but leave previous ones intact.
I understand how, behind the scenes, the original series would have to have its end date adjusted to the date prior to the selected event, and then a new series would have to be created with the new recurring event data.
Are there plans to add this functionality to the current delete/edit recurring event dialog? Or are there examples of how one would accomplish this?
Still loving the scheduler, and thanks in advance for any assistance with this.
Adam
I am using the ASP.NET MVC server side scheduler. What is noticeably missing is a way, when one chooses to delete/edit an entire series of a recurring event, to specify
1. Delete this entire series, or
2. Delete the highlighted event and all future events in the series, but leave previous ones intact.
I understand how, behind the scenes, the original series would have to have its end date adjusted to the date prior to the selected event, and then a new series would have to be created with the new recurring event data.
Are there plans to add this functionality to the current delete/edit recurring event dialog? Or are there examples of how one would accomplish this?
Still loving the scheduler, and thanks in advance for any assistance with this.
Adam
4 Answers, 1 is accepted
0
Hello Adam,
We do not have any immediate plans for the required functionality. Do you mind open a UserVoice discussion on the subject? This will help us to gather a valuable feedback for the feature.
With regards to the other question, the required behavior probably could be accomplished by manipulating the event in the save/remove event handler of the scheduler. Once the event is saved/removed you can modify the recurrenceRule field and thus achieve your goal.
Regards,
Georgi Krustev
Telerik
We do not have any immediate plans for the required functionality. Do you mind open a UserVoice discussion on the subject? This will help us to gather a valuable feedback for the feature.
With regards to the other question, the required behavior probably could be accomplished by manipulating the event in the save/remove event handler of the scheduler. Once the event is saved/removed you can modify the recurrenceRule field and thus achieve your goal.
Regards,
Georgi Krustev
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
Adam
Top achievements
Rank 1
answered on 29 Jan 2015, 02:20 PM
Good day,
I have been able to handle the Remove event, and can see how adding additional data to the data passed to the server would accomplish what I want. There is a snag, however, and I am hoping you could provide a little guidance.
In the onRemove handler, it appears I have two options, preventDefault or let the handler continue. I need user input, however. Throwing up a dialog does not make the handler "wait" until the user has dismissed a dialog. I have chosen not to use a confirm dialog. I was thinking something more custom like a Kendo Window. Javascript doesn't have a reliable Wait condition, where I can prevent the onRemove handler from finishing until I have acquired the user's delete notion.
I could add my delete options to the custom delete dialog supplied by the scheduler, but I don't see a template for that, and I would somehow have to communicate the user's choice to the remove handler.
How would you recommend going about this?
Thanks in advance,
Adam
I have been able to handle the Remove event, and can see how adding additional data to the data passed to the server would accomplish what I want. There is a snag, however, and I am hoping you could provide a little guidance.
In the onRemove handler, it appears I have two options, preventDefault or let the handler continue. I need user input, however. Throwing up a dialog does not make the handler "wait" until the user has dismissed a dialog. I have chosen not to use a confirm dialog. I was thinking something more custom like a Kendo Window. Javascript doesn't have a reliable Wait condition, where I can prevent the onRemove handler from finishing until I have acquired the user's delete notion.
I could add my delete options to the custom delete dialog supplied by the scheduler, but I don't see a template for that, and I would somehow have to communicate the user's choice to the remove handler.
How would you recommend going about this?
Thanks in advance,
Adam
0
Hello Adam,
In general, the best way to block a method execution is to use Html confirm dialog. The custom JavaScript solution will not wait for the user's input and the method will continue its execution.
I suppose that you can open a modal window from onRemove event handler with a custom form, but in this case you will need to prevent the function anyway and then perform the data source action manually.
I would suggest you use the available Html dialogs as they can block function execution and thus give you the desired user input.
If you still experiencing any difficulties to implement your requirement, I will need more details about it in order to assist you further.
Regards,
Georgi Krustev
Telerik
In general, the best way to block a method execution is to use Html confirm dialog. The custom JavaScript solution will not wait for the user's input and the method will continue its execution.
I suppose that you can open a modal window from onRemove event handler with a custom form, but in this case you will need to prevent the function anyway and then perform the data source action manually.
I would suggest you use the available Html dialogs as they can block function execution and thus give you the desired user input.
If you still experiencing any difficulties to implement your requirement, I will need more details about it in order to assist you further.
Regards,
Georgi Krustev
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
Adam
Top achievements
Rank 1
answered on 02 Feb 2015, 02:05 PM
Thanks for your reply, Georgi!
I have a solution that went a slightly different direction, but one I really like, and I will post the relevant code here, in case someone else wants to do this. I think this is a pretty critical feature, as most prime time calendar applications have some sort of "delete this and future events" in a series. Ok, here goes...
1. First things first. Add a Remove event handler in the Razor view to the scheduler...
2. Implement onRemove in the javascript file that accompanies the View...
First, I only need to do this on recurring rule events. If so, I capture the event in a global variable, as I will need it later for the result of the dialog I create in order to ask which delete option the user wants. Speaking of which, open that dialog, centering and refreshing it. The preventDefault is there to make sure nothing happens with the event yet on the server.
3. I need to know which event the user clicked from which I want to start the delete in the series, so capture that with another event handler on the scheduler, some javascript, and a global javascript variable for the date of the actual event clicked. Here are the two global variables in the JS file.
Here are the two events now on the scheduler...
Keep in mind, your scheduler needs to have selection enabled. Add this to your Html.Kendo().Scheduler<>()
4. Define the Kendo dialog box somewhere in your View file. This dialog will show your sweet new delete options and be launched by the above javascript!
5. Add the controller action that supplies the HTML for the view. This code isn't exciting, but it doesn't have to be.
6. The actual partial view.
7. Here is the cancel and delete javascript handlers for the two links at the bottom of the custom dialog. Right now, I have two options, delete the whole series, or just the event clicked and all subsequent events.
This is pretty important code. If everything important is not null, we are going to add the clicked event date (and a boolean I probably don't need) to the event payload that will go back to the server for the Destroy handler. Calling removeEvent on the scheduler directly, at this point, will launch the "delete this occurrence or series" Kendo dialog, and we are past that point already. So, I opted to remove the event entirely from the datasource and sync it with the server. This has the desired effect of invoking the Destroy event on the server. However, if the user selected "just this event and on..." I want the scheduler to display those events again, and hence the scheduler.dataSource.read() to refresh the view.
Here is the field code to add the extra two fields to the datasource in the View. You will have other fields on your schedule object, but for the sake of completeness...
8. Ok, now the hard part, and the fun part. The server needs to take the data and alter the event's recurrence properties if the user selected "delete this and future..." Here is my DestroyEvent code, minus stuff specific to my business.
Basically, I just want to adjust the recurrence rule to contain an "UNTIL=" item set to the day the user chose to end the series. That is the crux of my logic. All the rest of the solution has been to get my code to the point where on the server, I can adjust the recurrence rule of the event as such. The scheduledEvent.End property contains the ending time for the event on the date on which the event starts. So that part ended up being just adding days based on the date the user selected. I figured I had to remove any existing "COUNT=" or "UNTIL=" that already existed on the event, and replace them with the new one from this helper function.
And my sweet Kendo date formatting constant...
That's about it. I like the solution because (1) it seems to work and (2) the code is fairly straightforward and could be extended if other options were required.
I hope this helps if someone else is looking for the same functionality from the Kendo scheduler, which has been an enormous time saver and extremely easy to extend.
Adam
I have a solution that went a slightly different direction, but one I really like, and I will post the relevant code here, in case someone else wants to do this. I think this is a pretty critical feature, as most prime time calendar applications have some sort of "delete this and future events" in a series. Ok, here goes...
1. First things first. Add a Remove event handler in the Razor view to the scheduler...
.Events(e =>
{
e.Remove(
"onRemove"
);
})
2. Implement onRemove in the javascript file that accompanies the View...
function
onRemove(e) {
// On a remove, open the window to select delete options...
if
(e.event.recurrenceRule) {
recurringEvent = e.event;
var
window = $(
"#seriesDeleteOption"
).data(
"kendoWindow"
);
window.center();
window.refresh();
window.open();
e.preventDefault();
}
}
First, I only need to do this on recurring rule events. If so, I capture the event in a global variable, as I will need it later for the result of the dialog I create in order to ask which delete option the user wants. Speaking of which, open that dialog, centering and refreshing it. The preventDefault is there to make sure nothing happens with the event yet on the server.
3. I need to know which event the user clicked from which I want to start the delete in the series, so capture that with another event handler on the scheduler, some javascript, and a global javascript variable for the date of the actual event clicked. Here are the two global variables in the JS file.
var
selectedDate =
null
;
var
recurringEvent =
null
;
Here are the two events now on the scheduler...
.Events(e =>
{
e.Remove(
"onRemove"
);
e.Change(
"onChange"
);
})
function
onChange(e) {
// Store the selected event's date, in case we want to delete a series from this date forward...
selectedDate = e.start;
}
Keep in mind, your scheduler needs to have selection enabled. Add this to your Html.Kendo().Scheduler<>()
.Selectable(
true
)
4. Define the Kendo dialog box somewhere in your View file. This dialog will show your sweet new delete options and be launched by the above javascript!
@(Html.Kendo().Window()
.Name(
"seriesDeleteOption"
)
.Title(
"Delete Series"
)
.LoadContentFrom(
"DeleteOptionView"
,
"Instructor"
)
.Modal(
true
)
.Draggable()
.Visible(
false
)
.Width(400)
.Resizable()
.Position(position => position.Left(100).Top(100)))
5. Add the controller action that supplies the HTML for the view. This code isn't exciting, but it doesn't have to be.
public
ActionResult DeleteOptionView()
{
return
PartialView(
"_DeleteSeriesOptions"
);
}
6. The actual partial view.
<
div
>
<
div
class
=
"deleteSeriesOption"
>
<
input
type
=
"radio"
name
=
"deleteSeriesOption"
value
=
"0"
checked
=
"checked"
/><
label
for
=
"0"
>Delete this event and future events in the series</
label
>
</
div
>
<
div
class
=
"deleteSeriesOption"
>
<
input
type
=
"radio"
name
=
"deleteSeriesOption"
value
=
"1"
/><
label
for
=
"0"
>Delete all events in the series</
label
>
</
div
>
<
div
class
=
"deleteSeriesSubmit"
>
<
a
id
=
"submitDeleteChoice"
onclick
=
"closeDeleteOptions()"
>Continue</
a
>
<
a
id
=
"cancelDeleteChoice"
onclick
=
"cancelDeleteOptions()"
>Cancel</
a
>
</
div
>
</
div
>
7. Here is the cancel and delete javascript handlers for the two links at the bottom of the custom dialog. Right now, I have two options, delete the whole series, or just the event clicked and all subsequent events.
function
closeDeleteOptions(e) {
var
dialog = $(
"#seriesDeleteOption"
).data(
"kendoWindow"
);
var
theDate = selectedDate;
var
theEvent = recurringEvent;
// Now get the event and remove it, adding the data so the server sees it...
dialog.close();
if
(theDate !=
null
&& theEvent !=
null
) {
var
scheduler = $(
"#scheduler"
).data(
"kendoScheduler"
);
// If we want this one and forward deleted, pass extra goodies to the controller...
if
($(
"input[name=deleteSeriesOption]:checked"
).val() == 0) {
theEvent.DeleteForwardOnly =
true
;
theEvent.DeleteForwardDate = theDate.toDateString();
}
// We are ready to send the event back to the server for deletion...
// scheduler.removeEvent() will display the "delete series" dialog...
// to get around that, I alter the datasource with the item directly and sync...
scheduler.dataSource.remove(theEvent);
scheduler.dataSource.sync();
setTimeout(
function
() { scheduler.dataSource.read(); }, 100);
}
}
function
cancelDeleteOptions(e) {
var
window = $(
"#seriesDeleteOption"
).data(
"kendoWindow"
);
window.close();
}
This is pretty important code. If everything important is not null, we are going to add the clicked event date (and a boolean I probably don't need) to the event payload that will go back to the server for the Destroy handler. Calling removeEvent on the scheduler directly, at this point, will launch the "delete this occurrence or series" Kendo dialog, and we are past that point already. So, I opted to remove the event entirely from the datasource and sync it with the server. This has the desired effect of invoking the Destroy event on the server. However, if the user selected "just this event and on..." I want the scheduler to display those events again, and hence the scheduler.dataSource.read() to refresh the view.
Here is the field code to add the extra two fields to the datasource in the View. You will have other fields on your schedule object, but for the sake of completeness...
.DataSource(d => d
.Model(m =>
{
m.Id(f => f.EventId);
m.Field(f => f.Title);
m.Field(f => f.Description);
m.Field(f => f.Start);
m.Field(f => f.End);
m.Field(f => f.RecurrenceID);
m.Field(f => f.RecurrenceRule);
m.Field(f => f.RecurrenceException);
m.Field(f => f.IsAllDay);
m.Field(f => f.DeleteForwardOnly);
m.Field(f => f.DeleteForwardDate);
})
.Read(
"ReadEvents"
,
"Instructor"
)
.Create(
"CreateEvent"
,
"Instructor"
)
.Destroy(
"DestroyEvent"
,
"Instructor"
)
.Update(
"UpdateEvent"
,
"Instructor"
)
.Events(e => e.Error(
"error_handler"
))
)
8. Ok, now the hard part, and the fun part. The server needs to take the data and alter the event's recurrence properties if the user selected "delete this and future..." Here is my DestroyEvent code, minus stuff specific to my business.
public
virtual
JsonResult DestroyEvent([DataSourceRequest] DataSourceRequest request, ScheduleEvent scheduledEvent)
{
if
(ModelState.IsValid)
{
try
{
if
(scheduledEvent.DeleteForwardOnly && !String.IsNullOrEmpty(scheduledEvent.DeleteForwardDate))
{
// Just update the event to change it's end date to the day before...
DateTime dateToStartDeleting = DateTime.MinValue;
if
(DateTime.TryParse(scheduledEvent.DeleteForwardDate,
out
dateToStartDeleting))
{
// Adjust the end date (with time) until it's the day before the series is to be nuked...
var untilDate = scheduledEvent.End;
untilDate = untilDate.AddDays((dateToStartDeleting - untilDate).TotalDays);
// Adjust the recurrence rule to go a day before the day the series was deleted til...
scheduledEvent.RecurrenceRule = AdjustRecurrenceRule(scheduledEvent.RecurrenceRule, untilDate);
InstructionalEvent.Update(scheduledEvent.ToInstructionalEvent());
}
}
else
{
InstructionalEvent.Delete(scheduledEvent.EventId);
}
}
catch
(Exception ex)
{
Error.Create(ex);
throw
;
}
}
return
Json(
new
[] { scheduledEvent }.ToDataSourceResult(request, ModelState));
}
Basically, I just want to adjust the recurrence rule to contain an "UNTIL=" item set to the day the user chose to end the series. That is the crux of my logic. All the rest of the solution has been to get my code to the point where on the server, I can adjust the recurrence rule of the event as such. The scheduledEvent.End property contains the ending time for the event on the date on which the event starts. So that part ended up being just adding days based on the date the user selected. I figured I had to remove any existing "COUNT=" or "UNTIL=" that already existed on the event, and replace them with the new one from this helper function.
protected
string
AdjustRecurrenceRule(
string
originalRecurrence, DateTime newEndDate)
{
string
newRule = originalRecurrence;
var newList = originalRecurrence.Split(
';'
).ToList();
// Get rid of any existing UNTIL rules...
if
(newList.Any(r => r.Contains(
"UNTIL="
)))
{
var index = newList.IndexOf(newList.Single(r => r.Contains(
"UNTIL="
)));
newList.RemoveAt(index);
}
// Get rid of any existing COUNT rules...
if
(newList.Any(r => r.Contains(
"COUNT="
)))
{
var index = newList.IndexOf(newList.Single(r => r.Contains(
"COUNT="
)));
newList.RemoveAt(index);
}
newList.Add(
"UNTIL="
+ newEndDate.ToUniversalTime().ToString(Constants.KendoDateFormat));
newRule = String.Join(
";"
, newList);
return
newRule;
}
And my sweet Kendo date formatting constant...
public
const
string
KendoDateFormat =
"yyyyMMdd'T'HHmmss'Z'"
;
That's about it. I like the solution because (1) it seems to work and (2) the code is fairly straightforward and could be extended if other options were required.
I hope this helps if someone else is looking for the same functionality from the Kendo scheduler, which has been an enormous time saver and extremely easy to extend.
Adam