Multiple Editable Events for 1 Grid

6 posts, 0 answers
  1. Ruben
    Ruben avatar
    22 posts
    Member since:
    Sep 2017

    Posted 28 Sep 2017 Link to this post

    Okay, so I have a grid that is used to manage Users. I would like to have two edit-popup buttons,

    1.)   For changing the user's password 
    2.)   For changing the rest of the user's information

    I currently have 1 command.Edit() button that has a custom template specified in ".Editable" that works fine with changing the user's information.
    I would like to have a second button that is associated with a different template that changes the user's password. 

    I thought that this could be achieved through a Command.Custom() button; however, I'm not sure how I'd hook it up to the Grid's edit event. 
    Is this even possible? If not, is there any known workaround to achieve this functionality?

    Kind regards,
    Ruben

  2. Ruben
    Ruben avatar
    22 posts
    Member since:
    Sep 2017

    Posted 28 Sep 2017 in reply to Ruben Link to this post

    So, I just thought of a possible solution. If I have two "command.Edit()" buttons, one for changing the password and one for changing the rest of the user information. Like so, 

    columns.Command(command => command.Edit().UpdateText("Save User")).Title("Edit User").Width(60);
    columns.Command(command => command.Edit().UpdateText("Save Password")).Title("Edit Password").Width(60);

     

    I then define a template defined in Editable like so,

    .Editable(editable => editable
          .TemplateName("ManageUsersEditor")
          .Mode(GridEditMode.PopUp)
          .Window(window =>
          {
              window.HtmlAttributes(new { @class = "kendo-popup-editor" });
              window.Title("User account");
          })
          )

     

    I subscribe to the Edit Event like so,

    .Events(events => events.Edit("onEdit"))

     

    Could I add logic in the "onEdit" function to determine which Edit button was pressed? If so how would that logic look?

    <script>
        function onEdit(e) {
            // determine which edit button was pressed
            // can I do a check on the "Update Text" or any other field?
     
            if (!e.model.isNew()) {
                e.container.find(".passwordEditor").remove();
            }
        }
    </script>

     

     

    Any help is greatly appreciated! Thanks.

     

    Ruben

     

  3. Viktor Tachev
    Admin
    Viktor Tachev avatar
    2478 posts

    Posted 02 Oct 2017 Link to this post

    Hello Ruben,

    I am afraid that the described behavior is not available out of the box. However, you can implement it with a bit of additional code. 

    You can define a custom popup editor and wrap the editors in div elements that will be conditionally hidden when necessary. The popup editor can be roughly structured like below:


    <div class="customVisible">
     
        some custom editors that will be conditionally hidden
     
    </div>
     
    <div>
    other editors.
    </div>


    Then, you can specify custom command buttons:

    columns.Command(cmd => cmd.Custom("Edit1").Click("edit1Handler"));
    columns.Command(cmd => cmd.Custom("Edit2").Click("edit2Handler"));


    The Click handlers for each custom command will set a global variable that will determine what part of the editor will be visible to the user:


    var someFlag;
     
    function edit1Handler(e) {
         
        var grid = this;
        var row = $(e.target).closest("tr")[0];
        someFlag = "edit1";
     
        grid.editRow(row);
    }
     
    function edit2Handler(e) {
        var grid = this;
        var row = $(e.target).closest("tr")[0];
        someFlag = "edit2";
     
        grid.editRow(row);
    }


    Finally you can handle the Grid edit event and hide/show the relevant parts of the editor:

    .Events(e=>e.Edit("onEdit"))


    function onEdit(e) {
        if (someFlag == "edit1") {
     
            e.container.find(".customVisible").hide();
        }
    }


    Give the appraoch a try and let me know how it works for you.


    Regards,
    Viktor Tachev
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  4. Ruben
    Ruben avatar
    22 posts
    Member since:
    Sep 2017

    Posted 02 Oct 2017 in reply to Viktor Tachev Link to this post

    Hi Viktor, 

    Thank you for the help! I implemented your suggestion, and it works except for the password fields are autofilled with some erroneous data that I'm assuming might be the user information that I hid. Any idea how I could resolve this? Here is my current implementation: 

    // ManageUsers.cshtml
     
    @model ERMgtProgram.Models.ManageViewModels.ManageUsersViewModel
    @{
        ViewBag.Title = "Manage Users";
    }
    <h2>@ViewBag.Title.</h2>
    <h4>Modify data management accounts</h4>
    <p class="text-success">@ViewBag.StatusMessage</p>
    <div>
        @(Html.Kendo().Grid<ERMgtProgram.Models.ManageViewModels.ManageUsersViewModel>()
          .Name("manageUsersGrid")
          .Columns(columns =>
          {
              columns.Bound(c => c.FirstName).Width(100);
              columns.Bound(c => c.LastName).Width(100);
              columns.Bound(c => c.Email).Width(100);
              columns.Bound(c => c.RolesList).ClientTemplate("#= roleListDetails(data) #").Width(100).Sortable(false).Filterable(false).Groupable(false);
              columns.Command(command => command.Custom("Edit1").Click("edit1Handler")).Title("Edit User").Width(60);
              columns.Command(command => command.Custom("Edit2").Click("edit2Handler")).Title("Edit Password").Width(60);
              columns.Command(command => command.Destroy()).Title("Delete User").Width(60);
          })
          .Editable(editable => editable
                .TemplateName("ManageUsersEditor")
                .Mode(GridEditMode.PopUp)
                .Window(window =>
                {
                    window.HtmlAttributes(new { @class = "kendo-popup-editor" });
                    window.Title("User account");
                })
                )
          .ToolBar(toolbar =>
          {
              toolbar.Create().Text("Add new user");
          })
          .HtmlAttributes(new { style = "height: 700px;" })
          .Scrollable(s => s.Height(700))
          .Groupable()
          .Sortable()
          .Pageable(pageable => pageable
            .Refresh(true)
            .PageSizes(new int[] { 10, 20, 50, 100, 250, 1000 })
            .ButtonCount(5))
          .Filterable()
          .Events(events => events.Edit("onEdit"))
          .DataSource(dataSource => dataSource
            .Ajax()
            .Model(m =>
            {
                m.Id(c => c.Id);
                m.Field(c => c.Id).Editable(false);
                m.Field(c => c.RolesList);
            })
            .Events(events => events.RequestEnd("onRequestEnd").Error("errorHandler"))
            .Create(create => create.Action("Users_Create", "Manage").Data("sendAntiForgery"))
            .Read(read => read.Action("Users_Read", "Manage"))
            .Update(update => update.Action("Users_Edit", "Manage").Data("sendAntiForgery"))
            .Destroy(destroy => destroy.Action("Users_Delete", "Manage").Data("sendAntiForgery"))
            )
        )
    </div>
    <script>
        var someFlag;
     
        function edit1Handler(e) {
            var grid = this;
            var row = $(e.target).closest("tr")[0];
            someFlag = "edit1";
     
            grid.editRow(row);
        }
     
        function edit2Handler(e) {
            var grid = this;
            var row = $(e.target).closest("tr")[0];
            someFlag = "edit2";
     
            grid.editRow(row);
        }
    </script>
     
    <script>
        function onEdit(e) {
            // if model is not new then user pressed an edit button
            if (!e.model.isNew()) {
                if (someFlag == "edit1") {
                    e.container.find(".passwordEditor").hide();
                }
                else if (someFlag == "edit2") {
                    e.container.find(".userEditor").hide();
                }
            }
        }
    </script>
     
    <script>
        // displays server-side validation messages
        errorHandler = function (args) {
            if (args.errors) {
                var grid = $("#manageUsersGrid").data("kendoGrid");
                var validationTemplate = kendo.template($("#userDetailsValidationMessageTemplate").html());
                grid.one("dataBinding", function (e) {
                    e.preventDefault();
     
                    $.each(args.errors, function (propertyName) {
                        var renderedTemplate = validationTemplate({ field: propertyName, messages: this.errors });
                        grid.editable.element.find(".errors").append(renderedTemplate);
                    });
                });
            }
        };
    </script>
     
    <script type="text/x-kendo-template" id="userDetailsValidationMessageTemplate">
        # if (messages.length) { #
        <li>
            #=field#
            <ul>
                # for (var i = 0; i < messages.length; ++i) { #
                <li>#= messages[i] #</li>
                # } #
            </ul>
        </li>
        # } #
    </script>
     
    <script>
        // refreshes grid after create or update operations
        function onRequestEnd(e) {
            var grid = $("#manageUsersGrid").data("kendoGrid");
                var data = grid.dataSource;
                if (e.type == "create" || e.type == "update") {
                    if (!e.response.Errors)
                        data.read();
                }
            }
    </script>
     
    <script>
        // displays the roles for a particular user in a grid cell
        function roleListDetails(model) {
            var htm = "";
     
            for (var roleNumber in model.RolesList) {
                htm = htm + "<p> " + model.RolesList[roleNumber].Name + "</p>";
     
                if (roleNumber >= model.RolesList.length - 1) {
                    break;
                }
            }
            var html = kendo.format(htm);
     
            return html;
        }
    </script>
     
    <script>
        // posts antiforgery token
        function sendAntiForgery() {
            return { "__RequestVerificationToken": $('input[name=__RequestVerificationToken]').val() }
        }
    </script>

     

    // MangeUsersEditor.cshtml
     
    @using Kendo.Mvc.UI;
    @model ERMgtProgram.Models.ManageViewModels.ManageUsersViewModel
     
    <ul class="errors"></ul>
    <div class="userEditor">
        <div class="editor-label">
            @Html.LabelFor(m => m.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(m => m.FirstName)
            @Html.ValidationMessageFor(m => m.FirstName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(m => m.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(m => m.LastName)
            @Html.ValidationMessageFor(m => m.LastName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(m => m.Email)
        </div>
        <div class="editor-field">
            @Html.EditorFor(m => m.Email)
            @Html.ValidationMessageFor(m => m.Email)
        </div>
        <div class="editor-label">
            @Html.LabelFor(m => m.RolesList)
        </div>
        <div class="editor-field">
            @(Html.Kendo().MultiSelectFor(m => m.RolesList)
                            .DataTextField("Name")
                            .DataValueField("Id")
                            .IgnoreCase(true)
                            .AutoBind(true)
                                    .DataSource(datasource =>
                                    {
                                        datasource.Read(read => read.Action("ReadRolesList", "Manage"));
                                    })
            )
            @Html.ValidationMessageFor(m => m.RolesList)
        </div>
    </div>
    <div class="passwordEditor">
        <div class="editor-label">
            @Html.LabelFor(m => m.Password)
        </div>
        <div class="editor-field">
            @Html.EditorFor(m => m.Password)
            @Html.ValidationMessageFor(m => m.Password)
        </div>
        <div class="editor-label">
            @Html.LabelFor(m => m.ConfirmPassword)
        </div>
        <div class="editor-field">
            @Html.EditorFor(m => m.ConfirmPassword)
            @Html.ValidationMessageFor(m => m.ConfirmPassword)
        </div>
    </div>

     

    I've also attached some screenshots to give a visual representation of how it looks. Note: everything validates fine, but the password fields are autopopulated with erroneous data and instead I would like for them to be empty. 

     

  5. Ruben
    Ruben avatar
    22 posts
    Member since:
    Sep 2017

    Posted 02 Oct 2017 in reply to Ruben Link to this post

    Update: I am fairly confident that the password field is being auto-filled with the password hash stored in my User DB. 
  6. Ruben
    Ruben avatar
    22 posts
    Member since:
    Sep 2017

    Posted 03 Oct 2017 Link to this post

    Solution: I ended up just setting the password fields manually to override it, like so: 

    function edit2Handler(e) {
        var grid = this;
        var row = $(e.target).closest("tr")[0];
        someFlag = "edit2";
     
        grid.editRow(row);
     
        document.getElementById("Password").value = "";
        document.getElementById("ConfirmPassword").value = "";
    }

     

     

    Thanks for all the help!

Back to Top