ASP.NET Core Grid & Scheduler in RazorPages - Can't parse DateTime to DB and show List of Enum, Problems with Localization

1 Answer 83 Views
Date/Time Pickers Grid Localization Scheduler
Christopher
Top achievements
Rank 1
Christopher asked on 18 Jul 2024, 08:49 AM | edited on 18 Jul 2024, 09:18 AM

Hello,

I've got a RazorPages-Project with a Grid and a Scheduler.

I'm trying to add entries to the grid inline.

The simple text fields are working as expected but when trying to save the DateTime for Start and End, always the min value of DateTime is ending up being in the Start and End fields of the model. Moreover the list of enums is not shown correctly, I also tried it with a JS function to get the list in a ClientTemplate but that didn't work for me, now it shows [object Object]. Also the DefaultValue for title property is not set correctly. This is what I got so far.

Model:

    public class VisitViewModel : ISchedulerEvent
    {
        public int Id { get; set; }

        public string? Title { get; set; } = "";

        public string? Description { get; set; } = "";

        public bool IsAllDay { get; set; } = false;

        public string? StartTimezone { get; set; } = "";

        public string? EndTimezone { get; set; } = "";

        public string? RecurrenceRule { get; set; } = "";

        public string? RecurrenceException { get; set; } = "";

        public List<Departments>? Departments { get; set; } = new List<Departments>();

        [DataType(DataType.DateTime)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd.MM.yyyy HH:mm}")]
        public DateTime Start { get; set; }

        [DateGreaterThan(OtherField = "Start")]
        [DataType(DataType.DateTime)]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd.MM.yyyy HH:mm}")]
        public DateTime End { get; set; }

        public string Visitor { get; set; } = "";

        public string Company { get; set; } = "";

        public string Welcomer { get; set; } = "";
    }


Page:

@page
@model           .Pages.DetailsModel

@{
}

@using           .Data.Enum
@using           .ViewModels
@using Kendo.Mvc.UI

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@Html.AntiForgeryToken()


@(
Html.Kendo().Grid<VisitViewModel>()
            .Name("grid")
            .Editable(e => e.Mode(GridEditMode.InLine))
            .Scrollable(scrollable => scrollable.Endless(true))
            .Scrollable(a => a.Height("250px"))
            .ToolBar(x => x.Create())
            .Columns(columns =>
            {
                columns.Bound(column => column.Start).Width(250).Format("{0:dd.MM.yyyy HH:mm}").EditorTemplateName("DateTime");
                columns.Bound(column => column.End).Width(250).Format("{0:dd.MM.yyyy HH:mm}").EditorTemplateName("DateTime");
                columns.Bound(column => column.Visitor).Width(250);
                columns.Bound(column => column.Company).Width(250);
                columns.Bound(column => column.Welcomer).Width(250);
                columns.Bound(column => column.Departments).EditorTemplateName("Departments");
                columns.Bound(column => column.Description);
                columns.Command(column =>
                {
                    column.Edit();
                    column.Destroy();
                }).Width(230);
            })
            .DataSource(ds => ds.Ajax()
            .Read(r => r.Url("/Details?handler=Read").Data("forgeryToken"))
            .Update(u => u.Url("/Details?handler=Update").Data("forgeryToken"))
            .Create(c => c.Url("/Details?handler=Create").Data("forgeryToken"))
            .Destroy(d => d.Url("/Details?handler=Destroy").Data("forgeryToken"))
            .Model(m =>
            {
                m.Id(id => id.Id);

                m.Field(visit => visit.Title).DefaultValue("");

                m.Field(visit => visit.Departments).DefaultValue(new List<Departments>());

                m.Field(visit => visit.StartTimezone).DefaultValue("Etc/GMT+2");
                m.Field(visit => visit.EndTimezone).DefaultValue("Etc/GMT+2");

                m.Field(visit => visit.Start).DefaultValue(DateTime.Now);
                m.Field(visit => visit.End).DefaultValue(DateTime.Now);
            })
            .PageSize(5)
            )
            .Pageable()
)
@(
Html.Kendo().Scheduler<VisitViewModel>()
            .Name("scheduler")
            .Height(700)
            .DataSource(ds =>
            {
                ds.Read(r => r.Url("/Details?handler=Read").Data("forgeryToken"));
                ds.Update(u => u.Url("/Details?handler=Update").Data("forgeryToken"));
                ds.Create(c => c.Url("/Details?handler=Create").Data("forgeryToken"));
                ds.Destroy(d => d.Url("/Details?handler=Destroy").Data("forgeryToken"));
            })
)



<script type="text/javascript">
    function forgeryToken() {
        return kendo.antiForgeryTokens();
    } 
</script>

PageModel:

public class DetailsModel : PageModel
{
    private readonly          Context _context;

    public DetailsModel(         Context context)
    {
        _context = context;
    }

    public void OnGet()
    {
    }

    public override void OnPageHandlerExecuting(PageHandlerExecutingContext context)
    {
        CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("de-DE");

        base.OnPageHandlerExecuting(context);
    }

    public JsonResult OnPostRead([DataSourceRequest] DataSourceRequest request)
    {
        return new JsonResult(_context.VisitViewModels.ToDataSourceResult(request));
    }

    public JsonResult OnPostCreate([DataSourceRequest] DataSourceRequest request, VisitViewModel visit)
    {
        _context.VisitViewModels.Add(visit);
        _context.SaveChanges();

        return new JsonResult(new[] { visit }.ToDataSourceResult(request, ModelState));
    }

    public JsonResult OnPostUpdate([DataSourceRequest] DataSourceRequest request, VisitViewModel visit)
    {
        _context.VisitViewModels.Update(visit);
        _context.SaveChanges();
        return new JsonResult(new[] { visit }.ToDataSourceResult(request, ModelState));
    }

    public JsonResult OnPostDestroy([DataSourceRequest] DataSourceRequest request, VisitViewModel order)
    {
        _context.VisitViewModels.Remove(order);
        _context.SaveChanges();
        return new JsonResult(new[] { order }.ToDataSourceResult(request, ModelState));
    }
}

EditorTemplate DateTime

@model DateTime?

@(Html.Kendo().DateTimePickerFor(m => m).HtmlAttributes(new { title = Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("") }).Format("{0:dd.MM.yyyy HH:mm}"))

Furthermore I have problems with the language in my project, maybe this correlates. They are mixed up as you can see in the attachment.

 

Christopher
Top achievements
Rank 1
commented on 18 Jul 2024, 09:09 AM | edited

I was able to resolve the problem with the wrong DateTime in the model. After looking for errors in the Browser, I saw that the language file was not found. After adding the right path it worked. I also got the Title Property working, the default value of "" led to a null entry in the model. Changing it to test resolved the issue and test was the default value.

 

But still I can't manage to get the list of enums working.

Christopher
Top achievements
Rank 1
commented on 18 Jul 2024, 11:25 AM

Hello again,

 

I stumbled across another problem, I wanted to use a shared datasource for my grid and scheduler but I get an error which says:

"Uncaught ReferenceError: visitsDataSource is not defined"

 

I didn't add the the datasource to the scheduler yet.

 

Code Snippet:


@page
@model          .Pages.DetailsModel

@using          .Data.Enum
@using          .ViewModels
@using Kendo.Mvc.UI

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@Html.AntiForgeryToken()

@((Html.Kendo().DataSource<VisitViewModel>()
                            .Name("visitsDataSource")
                            .Ajax(ds => ds
                                .Read(r => r.Url("/Details?handler=Read").Data("forgeryToken"))
                                .Update(u => u.Url("/Details?handler=Update").Data("forgeryToken"))
                                .Create(c => c.Url("/Details?handler=Create").Data("forgeryToken"))
                                .Destroy(d => d.Url("/Details?handler=Destroy").Data("forgeryToken"))
                                .Model(m =>
                                {
                                    m.Id(visitViewModel => visitViewModel.Id);

                                    m.Field(visitViewModel => visitViewModel.Title).DefaultValue("Test");

                                    m.Field(visitViewModel => visitViewModel.Departments).DefaultValue(new List<Departments>());

                                    m.Field(visitViewModel => visitViewModel.StartTimezone).DefaultValue("Etc/GMT+2");
                                    m.Field(visitViewModel => visitViewModel.EndTimezone).DefaultValue("Etc/GMT+2");

                                    m.Field(visitViewModel => visitViewModel.Start).DefaultValue(DateTime.Now);
                                    m.Field(visitViewModel => visitViewModel.End).DefaultValue(DateTime.Now);
                                })
                                .PageSize(1)
    )
))

    @(
        Html.Kendo().Grid<VisitViewModel>()
        .Name("grid")
        .Editable(e => e.Mode(GridEditMode.InLine))
        .Scrollable(scrollable => scrollable.Endless(true))
        .Scrollable(a => a.Height("250px"))
        .ToolBar(x => x.Create())
        .Columns(columns =>
        {
            columns.Bound(column => column.Start).Width(250).Format("{0:dd.MM.yyyy HH:mm}").EditorTemplateName("DateTime");
            columns.Bound(column => column.End).Width(250).Format("{0:dd.MM.yyyy HH:mm}").EditorTemplateName("DateTime");
            columns.Bound(column => column.Visitor).Width(250);
            columns.Bound(column => column.Company).Width(250);
            columns.Bound(column => column.Welcomer).Width(250);
            columns.Bound(column => column.Departments).EditorTemplateName("Departments");
            columns.Bound(column => column.Description);
            columns.Command(column =>
            {
                column.Edit();
                column.Destroy();
            }).Width(230);
        })
        .DataSource("visitsDataSource")
        )



    @(
        Html.Kendo().Scheduler<VisitViewModel>()
        .Name("scheduler")
        .Height(700)
        .EventTemplate(Html.Kendo().Template()
        .AddHtml(@<div>
        <h5>
            ${data.Visitor}
        </h5>
        <p class="m-3">
            ${data.Company}
        </p>
    </div>
        )
        )
        .DataSource(ds => ds
        .Model(m =>
        {
            m.Id(visitViewModel => visitViewModel.Id);

            m.Field(visitViewModel => visitViewModel.Title).DefaultValue("Test");

            m.Field(visitViewModel => visitViewModel.Departments).DefaultValue(new List<Departments>());

            m.Field(visitViewModel => visitViewModel.StartTimezone).DefaultValue("Etc/GMT+2");
            m.Field(visitViewModel => visitViewModel.EndTimezone).DefaultValue("Etc/GMT+2");

            m.Field(visitViewModel => visitViewModel.Start).DefaultValue(DateTime.Now);
            m.Field(visitViewModel => visitViewModel.End).DefaultValue(DateTime.Now);
        })
        .Read(r => r.Url("/Details?handler=SchedulerRead").Data("forgeryToken"))
        .Update(u => u.Url("/Details?handler=Update").Data("forgeryToken"))
        .Create(c => c.Url("/Details?handler=Create").Data("forgeryToken"))
        .Destroy(d => d.Url("/Details?handler=Destroy").Data("forgeryToken"))
        )
        )

<script type="text/javascript">
    function forgeryToken() {
        return kendo.antiForgeryTokens();
    }
</script>

1 Answer, 1 is accepted

Sort by
0
Mihaela
Telerik team
answered on 23 Jul 2024, 07:03 AM

Hello Christopher,

1) "Departments" field

Since the "Departments" property is a List of "Departments" Model instances, you can display them in the Grid's column as a comma-separated list by using the ClientTemplateHandler() or ClientTemplate() methods:

  • ClientTemplateHandler()
columns.Bound(column => column.Departments).ClientTemplateHandler("showDepartments").EditorTemplateName("Departments");

<script>
    function showDepartments(data) {
        if (data.Departments) {
            var template = data.Departments.map(x => x.Name).join(', ') // loop through the records and map them by a nested property (i.e., "Name")
            return template;
        } else {
            return "";
        }
    }
</script>

//Model
    public class Departments
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }
  • ClientTemplate()
columns.Bound(column => column.Departments).ClientTemplate("#=showDepartments(data.Departments)#").EditorTemplateName("Departments");

<script>
    function showDepartments(Departments) {
        if (Departments) {
            var template = data.Departments.map(x => x.Name).join(', ')
            return template;
        } else {
            return "";
        }
    }
</script>

2) Shared DataSource - Move the "forgeryToken" function before the DataSource declaration. Otherwise, the DataSource throws a client-side error during initialization (check out the browser console).

<script type="text/javascript">
    function forgeryToken() {
        return kendo.antiForgeryTokens();
    }
</script>

@(Html.Kendo().DataSource<VisitViewModel>()
     .Name("visitsDataSource")
     ...
)

@(Html.Kendo().Grid<VisitViewModel>()
        .Name("grid")
        ...
        .DataSource("visitsDataSource")
)

Let me know if the issues are resolved at your end.


Regards,
Mihaela
Progress Telerik

Do you have a stake in the designеr-developer collaboration process? If so, take our survey to share your perspective and become part of this global research. You’ll be among the first to know once the results are out.
-> Start The State of Designer-Developer Collaboration Survey 2024

Tags
Date/Time Pickers Grid Localization Scheduler
Asked by
Christopher
Top achievements
Rank 1
Answers by
Mihaela
Telerik team
Share this question
or