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
5 Answers, 1 is accepted
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
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
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.
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!