grid inline editor with GreaterDateAttribute server validion

2 posts, 0 answers
  1. Michael
    Michael avatar
    50 posts
    Member since:
    May 2014

    Posted 20 Nov 2017 Link to this post

    Hi,

    I have inline editor in a grid.The validation from the server is working great, but I have 2 dates that one needs to be before the other.

    so I use GreaterDateAttribute and it's working good  on another window with regular form, but in the grid this specific validation doesn't appear in the client side like the others.

    someone can help?

    here is my grid:

    @(Html.Kendo().Grid<ProjectViewModel>()
                .Name("GridProjects")
                .Columns(columns =>
                {
                    columns.Bound(c => c.ProductID).Title("Product Id").Hidden();
                    columns.Bound(c => c.ProductName).Title("Product Name").Hidden();
                    columns.Bound(c => c.Name).Title("Name").Width(120);
                    columns.Bound(c => c.Leader.Name).EditorTemplateName("LeaderEditor").Title("Leader").Width(150)
                        .Filterable(f => f.UI("developersFilter")
                        .Mode(GridFilterMode.Row)
                        .Extra(false)
                        .Operators(operators => operators
                                        .ForString(str => str.Clear()
                                        .IsEqualTo("Is equal to"))));
                    columns.Bound(c => c.CodeReviewer.Name).EditorTemplateName("CodeReviewerEditor").Title("Code Reviewer").Width(150)
                        .Filterable(f => f.UI("developersFilter")
                            .Mode(GridFilterMode.Row)
                            .Extra(false)
                            .Operators(operators => operators
                                .ForString(str => str.Clear()
                                    .IsEqualTo("Is equal to"))));
                    columns.Bound(c => c.ActualStartDate).Title("Actual Start Date").EditorTemplateName("ActualStartDateEditor").Format("{0: MM/dd/yyyy}").Width(150);
                    columns.Bound(c => c.ActualEndDate).Title("Actual End Date").EditorTemplateName("ActualEndDateEditor").Format("{0: MM/dd/yyyy}").Width(150);
                    columns.Bound(c => c.EstimatedStartDate).Title("Estimated Start Date").Format("{0: MM/dd/yyyy}");
                    columns.Bound(c => c.EstimatedEndDate).Title("Estimated End Date").Format("{0: MM/dd/yyyy}");
                    columns.Bound(c => c.PercentCompleted).Title("Percent Completed").Width(130).ClientTemplate("<canvas id='chart_#=ID #' width='94' height='94' style='display: block; width: 94px; height: 94px;'></canvas>")/*ClientTemplate("#=kendo.format('{0:p2}', PercentCompleted / 100)#")*/;
                    columns.Command(command => { command.Edit(); command.Destroy(); }).Width(150);
                    columns.Command(command => command.Custom("ADDTASK").Text("Add Task").Click("addTask")).Title("Add Task").Width(150).HtmlAttributes(new { id = "addTaskButton" });
                })
                 .Groupable(g => g.Enabled(false))
                  .Filterable()
                  .ToolBar(toolbar =>
                  {
                      toolbar.Template(@<text>
            <div class="toolbar" style="float:left">
                <a class="k-button k-button-icontext" onclick='addProjectAjax()' href="#">
                    <span class="k-icon k-i-add"></span> ADD PROJECT
                </a>
                <a class="k-button k-grid-excel k-button-icontext" href="#">
                    <span class="k-icon k-i-excel"></span>Export to Excel
                </a>
            </div>
                    </text>);
                  })
                 .Resizable(resize => resize.Columns(true))
                 .Editable(editable => editable.Mode(GridEditMode.InLine))
                 .Excel(excel => excel
                                .AllPages(true)
                                .FileName("Projects.xlsx")
                                .Filterable(true)
                                .ForceProxy(true)
                                .ProxyURL(Url.Action("FileExportSave", "Home")))
                .Pageable(pager => pager
                                  .Refresh(true)
                                  .PageSizes(true)
                                  .PageSizes(new int[] { 6, 15, 20 })
                                  .ButtonCount(5))
                .Sortable(sortable =>
                {
                    sortable.SortMode(GridSortMode.MultipleColumn)
                   .Enabled(true);
                })
                .Scrollable()
                .Events(events => events.DataBound("onDataBoundSavedProjects").Cancel("createPieAfterCancellation"))
                .DataSource(dataSource => dataSource
                                         .Ajax()
                                         .Group(group => group.Add(p => p.ProductName))
                                         .PageSize(20)
                                         .Events(events => events.Error("errorHandlerProject"))
                                         .Read(read => read.Action("GetSavedProjects", "Project"))
                                         .Model(model =>
                                         {
                                             model.Id(item => item.ID);
                                             model.Field(a => a.EstimatedStartDate).Editable(false);
                                             model.Field(a => a.EstimatedEndDate).Editable(false);
                                             model.Field(a => a.PercentCompleted).Editable(false);
                                         })
                                         .Update(update => update.Action("UpdateProject", "Project"))
                                         .Destroy(update => update.Action("DeleteProject", "Project"))))

    here is my model:

      

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using TaskManagement.Contract;

    namespace TaskManagementUI.Models
    {
        public class ProjectViewModel
        {
         
            public int ID { get; set; }
            public int ProductID { get; set; }

            [Display(Name = "Product Name")]
            public string ProductName { get; set; }

            [Display(Name = "Name")]
            [Required(ErrorMessage = "Please enter name")]
            public string Name { get; set; }

            [Required(ErrorMessage = "Please select leader")]
            [Display(Name = "Leader")]
            public Developer Leader { get; set; }


            [Required(ErrorMessage = "Please select code reviewer")]
            [Display(Name = "Code Reviewer")]
            public Developer CodeReviewer { get; set; }

            public DateTime? EstimatedStartDate { get; set; }

            public DateTime? EstimatedEndDate { get; set; }

            [Required(ErrorMessage = "Please select a date")]
            [UIHint("DatePickerEditor")]
            [Display(Name = "Actual Start Date")]
            [DataType(DataType.Date)]
            public DateTime? ActualStartDate { get; set; }

            [Required(ErrorMessage = "Please select a date")]
            [UIHint("DatePickerEditor")]
            [Display(Name = "Actual End Date")]
            [GreaterDate(EarlierDateField = "ActualStartDate", ErrorMessage = "End date should be after Start date")]
            [DataType(DataType.Date)]
            public DateTime? ActualEndDate { get; set; }

            [UIHint("PercentCompletedEditor")]
            public int? PercentCompleted { get; set; }
            private List<ProjectManager> m_Managers;
            public List<ProjectManager> Managers
            {
                get
                {
                    if (m_Managers == null)
                    {
                        m_Managers = new List<ProjectManager>();
                        if (CodeReviewer != null)
                            m_Managers.Add(new ProjectManager { ProjectID = ID, DeveloperID = (int)CodeReviewer.ID, RoleId = RoleEnum.CodeReviewer });
                        if (Leader != null)
                            m_Managers.Add(new ProjectManager { ProjectID = ID, DeveloperID = (int)Leader.ID, RoleId = RoleEnum.Leader });
                    }
                    return m_Managers;

                }
                set
                {
                    m_Managers = new List<ProjectManager>();
                    if (CodeReviewer != null)
                        m_Managers.Add(new ProjectManager { ProjectID = ID, DeveloperID = (int) CodeReviewer.ID, RoleId = RoleEnum.CodeReviewer });
                    if (Leader != null)
                        m_Managers.Add(new ProjectManager { ProjectID = ID, DeveloperID = (int) Leader.ID, RoleId = RoleEnum.Leader });
                }
            }
            public List<Developer> Developers { get; set; }

        }
    }

    here is my class GreaterDateAttribute:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Web.Mvc;

    namespace TaskManagementUI.Models
    {
        [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
        public class GreaterDateAttribute : ValidationAttribute, IClientValidatable
        {
            public string EarlierDateField { get; set; }

            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                DateTime? date = value != null ? (DateTime?) value : null;
                var earlierDateValue = validationContext.ObjectType.GetProperty(EarlierDateField)
                    .GetValue(validationContext.ObjectInstance, null);
                DateTime? earlierDate = earlierDateValue != null ? (DateTime?) earlierDateValue : null;

                if (date.HasValue && earlierDate.HasValue && date <= Convert.ToDateTime(earlierDate).AddDays(-1))
                {
                    return new ValidationResult(ErrorMessage);
                }

                return ValidationResult.Success;
            }

            public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
            {
                var rule = new ModelClientValidationRule
                {
                    ErrorMessage = ErrorMessage,
                    ValidationType = "greaterdate"
                };

                rule.ValidationParameters["earlierdate"] = EarlierDateField;

                yield return rule;
            }
        }
    }

     

     

     

     

     

     

  2. Georgi
    Admin
    Georgi avatar
    574 posts

    Posted 22 Nov 2017 Link to this post

    Hello Michael,

    Internally the grid uses Kendo Validator for client-side validation. Using DataAnnotations attributes actually generates rules for the validator. However, not all DataAnnotation attributes are supported by the Kendo Validator.

    A possible solution is to extend the Validator with a custom rule which will validate the two date fields.

    The following demo demonstrates how to create custom validation rule:


    In the code block below you will find an example on how to validate whether end time is after start time:

    //register custom validation rules
    (function ($, kendo) {
        $.extend(true, kendo.ui.validator, {
            rules: { // custom rules
                dateValidation: function (input, params) {
                    if (input.is("[name='ActualStartDate']") && input.val() != "") {
     
                        var startDate = kendo.parseDate(input.val());
                        var endDate = kendo = kendo.parseDate($('#ActualEndDate').val());
     
                        return startDate.getTime() < endDate.getTime();
                    } else if (input.is("[name='ActualEndDate']") && input.val() != "") {
                        var endDate = kendo.parseDate(input.val());
                        var startDate = kendo = kendo.parseDate($('#ActualStartDate').val());
     
                        return startDate.getTime() < endDate.getTime();
                    }
     
                    return true;
                }
            },
            messages: { //custom rules messages
                dateValidation: function (input) {
                    // return the message text
                    return input.attr("data-val-dateValidation");
                }
            }
        });
    })(jQuery, kendo);


    Regards,
    Georgi
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top