JavaScript UI Libraries & Blazor Components Suite – Smart UI › Forums › Scheduler › Custom edit Component in Angular for Scheduler
Tagged: customize event
- This topic has 7 replies, 5 voices, and was last updated 3 months, 1 week ago by Markov.
-
AuthorPosts
-
January 23, 2023 at 9:15 am #104271Andrea DurandoParticipant
Hi all,
Is it possible to customize the Edit window for the schduler with a custom Angular Component?
In the docs I see that is possible to do that , but only with javascript.
January 23, 2023 at 4:02 pm #104275ivanpeevskiParticipantHi Andrea,
The structure of the Editing window can be fully customized, including with custom Angular Components.
Here is an example of creating a custom Editing Window with multiple different Smart Angular components: codesandbox
If you experience any difficulties, please do not hesitate to contact us again!
Best Regards,
Ivan Peevski
Smart UI Team
https://www.htmlelements.com/January 2, 2024 at 1:09 am #109610Lukas XaverParticipantHi Ivan,
Is there any chance to get an example for blazor?
I tried to copy over your custom window but I won’t get it to work.Best Regards,
LukasJanuary 2, 2024 at 9:32 am #109616MarkovKeymasterThe guide below details how to implement Custom Window Editor for Scheduler in Blazor. In the cases when you need to create additional custom fields, which are not supported by the default Editing Window, Smart.Scheduler allows you to replace it with an entirely custom one, which will handle the update/insert operations instead. Create Scheduler and Custom Window First, we need to create our Scheduler. The code below setups a basic Scheduler with multiple Events: <Scheduler @ref=scheduler DataSource="dataSource" View="SchedulerViewType.Month"></Scheduler> @code{ Scheduler scheduler; List<SchedulerDataSource> dataSource = new List<SchedulerDataSource>() { new SchedulerDataSource() { Id = "1", Label = "Google AdWords Strategy", DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+1, 10, 0, 0), DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day +1, 11, 30, 0), BackgroundColor = "#E67C73", }, new SchedulerDataSource() { Id = "3", Label = "New Brochures", DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+3, 12, 0, 0), DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+3, 15, 0, 0), BackgroundColor = "#8E24AA" }, new SchedulerDataSource() { Id = "3", Label = "Brochure Design Review", DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+6, 15, 30, 0), DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+6, 18, 15, 0), }, }; } Then we should add the HTML of our Custom Editing Window. The Window in this demo features a Text Input, DateTime Pickers, DropDownList inputs and a Star Rating Input: <Window @ref="window" Modal="true"> <h3>@heading</h3> <table> <tr> <td> <div class="smart-control"> <label>Label<br /></label> <Input @ref="labelInput" Placeholder="Event label"></Input> </div> </td> <td></td> </tr> <tr> <td> <div class="smart-control"> <label>Date Start</label> <DateTimePicker @ref="dateStartInput" FormatString="D" CalendarButton="true" DropDownAppendTo="body"></DateTimePicker> </div> </td> <td> <div class="smart-control"> <label>Date End</label> <DateTimePicker @ref="dateEndInput" FormatString="D" CalendarButton="true" DropDownAppendTo="body"></DateTimePicker> </div> </td> </tr> <tr> <td> <div class="smart-control"> <label>Department</label> <DropDownList @ref="departmentInput"> <ListItem Value="sales">Sales</ListItem> <ListItem Value="marketing">Marketing</ListItem> <ListItem Value="finance">Finance</ListItem> <ListItem Value="technical">IT</ListItem> </DropDownList> </div> </td> <td> <div class="smart-control"> <label>Office Location</label> <DropDownList @ref="locationInput"> <ListItem Value="new_york">New York</ListItem> <ListItem Value="los_angeles">Los Angeles</ListItem> <ListItem Value="chicago">Chicago</ListItem> <ListItem Value="houston">Houston</ListItem> </DropDownList> </div> </td> </tr> <tr> <td> <div class="smart-control"> <label>Background Color</label> <ColorInput @ref="backgroundColorInput"></ColorInput> </div> </td> <td> <div class="smart-control"> <label>Rating </label> <Rating @ref="ratingInput"></Rating> </div> </td> </tr> </table> <div style="margin-top: 20px;"> <Button @ref="cancelButton" OnClick="CloseWindow">Cancel</Button> <Button @ref="saveButton" OnClick="SaveChanges">Save</Button> </div> </Window> @code{ Scheduler scheduler; Window window; string heading = "Create an Event"; Input labelInput; DateTimePicker dateStartInput, dateEndInput; DropDownList departmentInput, locationInput; ColorInput backgroundColorInput; Rating ratingInput; Button cancelButton, saveButton; bool editing = false; int editingIndex = -1; } Finally, add the CSS to format the content inside: smart-window { --smart-window-default-height: 450px; --smart-window-default-width: 600px; --smart-window-header-height: 35px; } .smart-window .smart-content-container>.smart-content { align-items: baseline; } #repeat-editor { margin-top: 10px; } #repeat-editors>div { margin-top: 10px; } #repeat-editors smart-date-time-picker { width: 100px; } #repeat-editors smart-number-input { width: 100px; } smart-radio-button { margin-left: 10px; padding: 5px; } .radio-button-wrapper { display: flex; align-items: center; margin-top: 5px; } .submit-btn { margin-left: 15px; --smart-background: #005b98; --smart-background-color: white; } table td { padding-top: 10px; } Replace Default Window In order to replace the default Window, we will need to use onReady and the OnEditDialogOpening event. In the OnReady Event, use JSInterop to call the "preventWindowOpening" JS function, which we will later create. @inject IJSRuntime JS <Scheduler @ref=scheduler DataSource="dataSource" View="SchedulerViewType.Month" OnEditDialogOpening="OnEditDialogOpening" OnReady="OnReady"></Scheduler> @code{ ... private void OnReady(Scheduler scheduler) { JS.InvokeVoidAsync("preventWindowOpening"); } } In the _Host.cshtml, add the "preventWindowOpening" JS function, which will simply prevent the default window from opening: <script> (function (global) { global.preventWindowOpening = function () { const scheduler = document.querySelector('smart-scheduler'); scheduler.addEventListener('editDialogOpening', function(event){ event.preventDefault(); }); } })(window); </script> Next, attach the "OnEditDialogOpening" event to the Scheduler. The function will first check whether the users is attempting to insert a new Event or modify an existing one. If the operation is insertion, it will open an empty Editing Window. If it is editing, the function will find the index of the selected Event and open the Editing Window with the Event's data filled-in. private async void OnEditDialogOpening(Event ev){ SchedulerEditDialogOpeningEventDetail args = ev["Detail"]; Dictionary<string, string> item = args.Item.ToObject<Dictionary<string, string>>(); editing = item.ContainsKey("label"); if (editing) { FillWindow(item); var events = await scheduler.GetDataSourceAsync(); //find the index of the item in the events array using the id property for(int i = 0; i < events.Count(); i++) { //System.Text.Json.JsonElement currentEvent = events[i]; SchedulerDataSource currentEvent = events.ElementAt(i) as SchedulerDataSource; if (item["id"] == currentEvent.Id) { editingIndex = i; } } } else { ResetWindow(item["dateStart"], item["dateEnd"]); } window.Open(); } Custom Window Repeating Events Smart.Scheduler Events can also be set as repeating. For example, a birthday reminder every year or a work meeting every Monday morning. Now we will add the editors, which will allow the user to set the repeating options. function repeatChange(event) { const checked = event.detail.value; const element = document.querySelector('#editing-window "#repeat-editor"'); if (checked) { element.style.display = "block"; } else { element.style.display = "none"; } setRepeatEditor("daily"); } function repeatFreqChange(event) { let selectedValue = event.detail.value.toLowerCase(); this.setRepeatEditor(selectedValue); } function setRepeatEditor(type) { const window = document.querySelector('#editing-window "#repeat-editor"'); window.innerHTML = ""; const repeatFreqEditor = document.createElement("div"); const repeatFreqLabel = document.createElement("div"); let word; switch (type) { case "hourly": word = "hours"; break; case "daily": word = "days"; break; case "weekly": word = "weeks"; break; case "monthly": word = "months"; break; case "yearly": word = "years"; break; } repeatFreqLabel.innerHTML = <code>Repeat every (${word})</code>; repeatFreqEditor.appendChild(repeatFreqLabel); const repeatInterval = document.createElement("smart-number-input"); repeatInterval.id = "repeatInterval"; repeatInterval.min = 1; repeatFreqEditor.appendChild(repeatInterval); window.appendChild(repeatFreqEditor); if (type === "weekly" || type === "monthly" || type === "yearly") { const repeatOnEditor = document.createElement("div"); const repeatOnLabel = document.createElement("label"); repeatOnLabel.innerHTML = "Repeat on "; repeatOnEditor.appendChild(repeatOnLabel); if (type === "weekly") { const repeatOn = document.createElement("smart-button-group"); repeatOn.id = "repeatOn"; repeatOn["selectionMode"] = "zeroOrMany"; repeatOn.dataSource = [{ label: "Mon", value: "1" }, { label: "Tue", value: "2" }, { label: "Wed", value: "3" }, { label: "Thu", value: "4" }, { label: "Fri", value: "5" }, { label: "Sat", value: "6" }, { label: "Sun", value: "0" } ]; repeatOnEditor.appendChild(repeatOn); } else if (type === "monthly") { const repeatOn = document.createElement("smart-number-input"); repeatOn.id = "repeatOn"; repeatOn.min = 1; repeatOn.max = 31; repeatOnEditor.appendChild(repeatOn); } else if (type === "yearly") { repeatOnEditor.style.display = "flex"; repeatOnEditor.style.alignItems = "center"; const repeatOn = document.createElement("smart-drop-down-list"); repeatOn.id = "repeatOn"; repeatOn.dataSource = [{ label: "January", value: "0" }, { label: "February", value: "1" }, { label: "March", value: "2" }, { label: "April", value: "3" }, { label: "May", value: "4" }, { label: "June", value: "5" }, { label: "July", value: "6" }, { label: "August", value: "7" }, { label: "September", value: "8" }, { label: "October", value: "9" }, { label: "November", value: "10" }, { label: "December", value: "11" } ]; repeatOnEditor.appendChild(repeatOn); const repeatOnDay = document.createElement("smart-number-input"); repeatOnDay.id = "repeatOnDay"; repeatOnDay.min = 1; repeatOnDay.max = 31; repeatOnEditor.appendChild(repeatOnDay); } window.appendChild(repeatOnEditor); } const endRepeatEditor = document.createElement("div"); const endRepeatLabel = document.createElement("div"); endRepeatLabel.innerHTML = "End repeat"; endRepeatEditor.appendChild(endRepeatLabel); const neverWrapper = document.createElement("div"); neverWrapper.classList.add("radio-button-wrapper"); neverWrapper.innerHTML = "<smart-radio-button group-name='repeat' id='never' checked>Never</smart-radio-button>"; endRepeatEditor.appendChild(neverWrapper); const onWrapper = document.createElement("div"); onWrapper.classList.add("radio-button-wrapper"); onWrapper.innerHTML =
<smart-radio-button group-name=’repeat’ id=’on’>On</smart-radio-button>
<smart-date-time-picker id=’dateOfRepeat’ formatString=”dd MM yyyy” calendar-button drop-down-append-to=”body” disabled></smart-date-time-picker>`;
endRepeatEditor.appendChild(onWrapper);
const afterWrapper = document.createElement(“div”);
afterWrapper.classList.add(“radio-button-wrapper”);
afterWrapper.innerHTML =
“<smart-radio-button group-name=’repeat’ id=’after’>After</smart-radio-button><smart-number-input id=’repeatAfter’ min=’1′ disabled></smart-number-input>occurrences”;
endRepeatEditor.appendChild(afterWrapper);
Array.from(endRepeatEditor.querySelectorAll(“smart-radio-button”)).forEach(
(button) => {
button.addEventListener(“checkValue”, (event) => {
const target = event.target;
//disable the other inputs
if (target.id === “never”) {
(onWrapper.querySelector(
“smart-date-time-picker”
)).disabled = true;
(afterWrapper.querySelector(
“smart-number-input”
)).disabled = true;
} else if (target.id === “on”) {
(onWrapper.querySelector(
“smart-date-time-picker”
)).disabled = false;
(afterWrapper.querySelector(
“smart-number-input”
)).disabled = true;
} else if (target.id === “after”) {
(onWrapper.querySelector(
“smart-date-time-picker”
)).disabled = true;
(afterWrapper.querySelector(
“smart-number-input”
)).disabled = false;
}
});
}
);
window.appendChild(endRepeatEditor);
}
Repeat Editors
Reset & Fill Window Content
The ResetWindow function is called when the user attempts to insert a new Event. It empties all fields and sets the date inputs to the time slot selected by the user:private void ResetWindow(string dateStart, string dateEnd)
{
heading = “Create an Event”;
labelInput.Value = “”;
dateStartInput.SetDate(DateTime.ParseExact(dateStart, “MM/dd/yyyy HH:mm:ss”, null));
dateEndInput.SetDate(DateTime.ParseExact(dateEnd, “MM/dd/yyyy HH:mm:ss”, null));
departmentInput.SelectedIndexes = new int[] { 0 };
locationInput.SelectedIndexes = new int[] { 0 };
backgroundColorInput.Value = “”;
ratingInput.Value = 1;
}
The FillWindow receives a scheduler event and fill the event’s data inside the Winow Fields:private void FillWindow(Dictionary schedulerEvent)
{
heading = “Edit an Event”;
labelInput.Value = schedulerEvent[“label”];
dateStartInput.SetDate(DateTime.ParseExact(schedulerEvent[“dateStart”], “MM/dd/yyyy HH:mm:ss”, null));
dateEndInput.SetDate(DateTime.ParseExact(schedulerEvent[“dateEnd”], “MM/dd/yyyy HH:mm:ss”, null));
departmentInput.Select(schedulerEvent.GetValueOrDefault(“department”, “sales”));
locationInput.Select(schedulerEvent.GetValueOrDefault(“location”, “new_york”));
backgroundColorInput.Value = schedulerEvent.GetValueOrDefault(“backgroundColor”, “”);
ratingInput.Value = int.Parse(schedulerEvent.GetValueOrDefault(“rating”, “1”));
}
Fill Window Content
Save Changes
Finally, we need to add the saveChanges() function which will be called when the user clicks the ‘Save’ button.
The function should take the values from the editors and cheched whether it should modify an existing Event or create a new one.private async void SaveChanges()
{
object eventObject = new {
id = (DateTime.Now).ToString(“yyyyMMddHHmmssffff”),
label = labelInput.Value,
dateStart = await dateStartInput.GetDate(),
dateEnd = await dateEndInput.GetDate(),
department = departmentInput.SelectedValues[0],
location = locationInput.SelectedValues[0],
backgroundColor = backgroundColorInput.Value,
rating = ratingInput.Value
};
if (editing && editingIndex > -1)
{
scheduler.UpdateEvent(editingIndex, eventObject);
}
else
{
scheduler.AddEvent(eventObject);
}
window.Close();
}
Now, the custom Editing Window is complete. The full code is below:
@page “/”
@inject IJSRuntime JS
<PageTitle>Scheduler</PageTitle><Scheduler @ref=scheduler DataSource=”dataSource” View=”SchedulerViewType.Month” OnEditDialogOpening=”OnEditDialogOpening” OnReady=”OnReady”></Scheduler>
<Window @ref=”window” Modal=”true”>
<h3>@heading</h3>
<table>
<tr>
<td>
<div class=”smart-control”>
<label>Label<br /></label>
<Input @ref=”labelInput” Placeholder=”Event label”></Input>
</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class=”smart-control”>
<label>Date Start</label>
<DateTimePicker @ref=”dateStartInput” FormatString=”D” CalendarButton=”true”
DropDownAppendTo=”body”></DateTimePicker>
</div>
</td>
<td>
<div class=”smart-control”>
<label>Date End</label>
<DateTimePicker @ref=”dateEndInput” FormatString=”D” CalendarButton=”true”
DropDownAppendTo=”body”></DateTimePicker>
</div>
</td>
</tr>
<tr>
<td>
<div class=”smart-control”>
<label>Department</label>
<DropDownList @ref=”departmentInput”>
<ListItem Value=”sales”>Sales</ListItem>
<ListItem Value=”marketing”>Marketing</ListItem>
<ListItem Value=”finance”>Finance</ListItem>
<ListItem Value=”technical”>IT</ListItem>
</DropDownList>
</div>
</td>
<td>
<div class=”smart-control”>
<label>Office Location</label>
<DropDownList @ref=”locationInput”>
<ListItem Value=”new_york”>New York</ListItem>
<ListItem Value=”los_angeles”>Los Angeles</ListItem>
<ListItem Value=”chicago”>Chicago</ListItem>
<ListItem Value=”houston”>Houston</ListItem>
</DropDownList>
</div>
</td>
</tr>
<tr>
<td>
<div class=”smart-control”>
<label>Background Color</label>
<ColorInput @ref=”backgroundColorInput”></ColorInput>
</div>
</td>
<td>
<div class=”smart-control”>
<label>Rating </label>
<Rating @ref=”ratingInput”></Rating>
</div>
</td>
</tr>
</table>
<div style=”margin-top: 20px;”>
<Button @ref=”cancelButton” OnClick=”CloseWindow”>Cancel</Button>
<Button @ref=”saveButton” OnClick=”SaveChanges”>Save</Button>
</div>
</Window>@code{
Scheduler scheduler;
Window window;
string heading = “Create an Event”;
Input labelInput;
DateTimePicker dateStartInput, dateEndInput;
DropDownList departmentInput, locationInput;
ColorInput backgroundColorInput;
Rating ratingInput;
Button cancelButton, saveButton;bool editing = false; int editingIndex = -1;
List<SchedulerDataSource> dataSource = new List<SchedulerDataSource>()
{
new SchedulerDataSource()
{
Id = “1”,
Label = “Google AdWords Strategy”,
DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+1, 10, 0, 0),
DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day +1, 11, 30, 0),
BackgroundColor = “#E67C73”,},
new SchedulerDataSource()
{
Id = “3”,
Label = “New Brochures”,
DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+3, 12, 0, 0),
DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+3, 15, 0, 0),
BackgroundColor = “#8E24AA”
},
new SchedulerDataSource()
{
Id = “3”,
Label = “Brochure Design Review”,
DateStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+6, 15, 30, 0),
DateEnd = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+6, 18, 15, 0),
},
};private void ResetWindow(string dateStart, string dateEnd)
{
heading = “Create an Event”;
labelInput.Value = “”;
dateStartInput.SetDate(DateTime.ParseExact(dateStart, “MM/dd/yyyy HH:mm:ss”, null));
dateEndInput.SetDate(DateTime.ParseExact(dateEnd, “MM/dd/yyyy HH:mm:ss”, null));
departmentInput.SelectedIndexes = new int[] { 0 };
locationInput.SelectedIndexes = new int[] { 0 };
backgroundColorInput.Value = “”;
ratingInput.Value = 1;
}private void FillWindow(Dictionary<string, string> schedulerEvent)
{
heading = “Edit an Event”;
labelInput.Value = schedulerEvent[“label”];
dateStartInput.SetDate(DateTime.ParseExact(schedulerEvent[“dateStart”], “MM/dd/yyyy HH:mm:ss”, null));
dateEndInput.SetDate(DateTime.ParseExact(schedulerEvent[“dateEnd”], “MM/dd/yyyy HH:mm:ss”, null));
departmentInput.Select(schedulerEvent.GetValueOrDefault(“department”, “sales”));
locationInput.Select(schedulerEvent.GetValueOrDefault(“location”, “new_york”));
backgroundColorInput.Value = schedulerEvent.GetValueOrDefault(“backgroundColor”, “”);
ratingInput.Value = int.Parse(schedulerEvent.GetValueOrDefault(“rating”, “1”));
}private async void OnEditDialogOpening(Event ev){
SchedulerEditDialogOpeningEventDetail args = ev[“Detail”];
Dictionary<string, string> item = args.Item.ToObject<Dictionary<string, string>>();
editing = item.ContainsKey(“label”);
if (editing)
{
FillWindow(item);
var events = await scheduler.GetDataSourceAsync();
//find the index of the item in the events array using the id property
for(int i = 0; i < events.Count(); i++)
{
//System.Text.Json.JsonElement currentEvent = events[i];
SchedulerDataSource currentEvent = events.ElementAt(i) as SchedulerDataSource;
if (item[“id”] == currentEvent.Id)
{
editingIndex = i;
}
}
}
else
{
ResetWindow(item[“dateStart”], item[“dateEnd”]);
}
window.Open();}
private void OnReady(Scheduler scheduler)
{
JS.InvokeVoidAsync(“replaceWindow”);
}private void CloseWindow()
{
window.Close();
}private async void SaveChanges()
{
object eventObject = new {
id = (DateTime.Now).ToString(“yyyyMMddHHmmssffff”),
label = labelInput.Value,
dateStart = await dateStartInput.GetDate(),
dateEnd = await dateEndInput.GetDate(),
department = departmentInput.SelectedValues[0],
location = locationInput.SelectedValues[0],
backgroundColor = backgroundColorInput.Value,
rating = ratingInput.Value
};
if (editing && editingIndex > -1)
{
scheduler.UpdateEvent(editingIndex, eventObject);
}
else
{
scheduler.AddEvent(eventObject);
}
window.Close();
}}
<style>
smart-window {
–smart-window-default-height: 450px;
–smart-window-default-width: 600px;
–smart-window-header-height: 35px;
}.smart-window .smart-content-container>.smart-content {
align-items: baseline;
}#repeat-editor {
margin-top: 10px;
}#repeat-editors>div {
margin-top: 10px;
}#repeat-editors smart-date-time-picker {
width: 100px;
}#repeat-editors smart-number-input {
width: 100px;
}smart-radio-button {
margin-left: 10px;
padding: 5px;
}.radio-button-wrapper {
display: flex;
align-items: center;
margin-top: 5px;
}.submit-btn {
margin-left: 15px;
–smart-background: #005b98;
–smart-background-color: white;
}table td {
padding-top: 10px;
}
</style>`January 3, 2024 at 4:53 pm #109618Lukas XaverParticipantHej markov,
Thanks for the tutorial!
Could you provide me the link to this tutorial?
Maybe there is more I could use / search in the future 🙂Best regards,
LukasJanuary 3, 2024 at 5:42 pm #109619MarkovKeymasterHi Lukas,
It is available only in my post 🙂
July 2, 2024 at 1:19 pm #111083Srinivas DuggiralaParticipantHi Team,
I am unable to open codesandbox , could you please provide stackblitz project or documentation for the same,
Thanks
July 4, 2024 at 5:20 am #111103MarkovKeymasterHi,
You can look at https://www.htmlelements.com/docs/scheduler-windows/. This help topic also shows how to customize the edit window.
Best regards,
MarkovSmart UI Team
https://www.htmlelements.com/ -
AuthorPosts
- You must be logged in to reply to this topic.