Hi,
I am trying to create a permissions view for my MVC 4 application.
What I want to achieve is that the selection made on the users table, populates the payrolls this person can access in a second table, then by selecting a payroll from the second table I would like it to display the permissions that user has within the selected payroll. So exactly like this http://demos.telerik.com/aspnet-ajax/grid/examples/clientmasterdetails/defaultcs.aspx but three tables instead of 2.
I can get a grid to populate with the users but where I am strugling is getting the selected user to query the payrolls and populate the payrolls table. I am quite new to all this so I am not quite sure how the selection gets the data and renders the grid? Does this call an ajax action in the view controller? And how is the second grid element then rendered? Does it re-render the first grid with the list of users again or will this persits?
My controller so far is like this NB the ReadPay and ReadPay Functions and all the ViewData in the Index action are my attempts to get this to work so please ignore them if they are wrong and point me in the right direction if possible please:
This is my view so far, again the second grid code and the selectable: true in the first grid are my attempts to get this to work:
Your help will be greatly appreciated!
Andy
I am trying to create a permissions view for my MVC 4 application.
What I want to achieve is that the selection made on the users table, populates the payrolls this person can access in a second table, then by selecting a payroll from the second table I would like it to display the permissions that user has within the selected payroll. So exactly like this http://demos.telerik.com/aspnet-ajax/grid/examples/clientmasterdetails/defaultcs.aspx but three tables instead of 2.
I can get a grid to populate with the users but where I am strugling is getting the selected user to query the payrolls and populate the payrolls table. I am quite new to all this so I am not quite sure how the selection gets the data and renders the grid? Does this call an ajax action in the view controller? And how is the second grid element then rendered? Does it re-render the first grid with the list of users again or will this persits?
My controller so far is like this NB the ReadPay and ReadPay Functions and all the ViewData in the Index action are my attempts to get this to work so please ignore them if they are wrong and point me in the right direction if possible please:
using
System;
using
System.Collections.Generic;
using
System.Data;
using
System.Data.Entity;
using
System.Linq;
using
System.Web;
using
System.Web.Mvc;
using
PayPlate.Models;
using
PayPlate.DAL;
using
PagedList;
namespace
PayPlate.Controllers
{
public
class
UserController : Controller
{
UnitOfWork unitOfWork =
new
UnitOfWork();
public
ActionResult Index(Int32 ? uid, Int32 ? pid)
{
ViewData[
"Users"
] = Read();
if
(uid ==
null
)
{
uid = unitOfWork.UserRepository.Get().FirstOrDefault().UserID;
}
ViewData[
"uid"
] = uid;
ViewData[
"Payrolls"
] = ReadPay(uid.Value);
if
(pid ==
null
)
{
pid = unitOfWork.UserRepository.Get(i => i.UserID == uid).Single().Permissions.Select(p => p.PayrollID).Distinct().FirstOrDefault();
}
ViewData[
"pid"
] = pid;
ViewData[
"Permissions"
] = ReadPerm(uid.Value, pid.Value);
return
View();
}
public
IEnumerable<Payroll> ReadPay(Int32 uid)
{
var pays = unitOfWork.UserRepository.Get(i => i.UserID == uid).Single().Permissions.Select(p => p.Payroll).Distinct();
// Use a view model to avoid serializing internal Entity Framework properties as JSON
pays = pays.Select(p =>
new
Payroll
{
PayrollID = p.PayrollID,
Title = p.Title,
C21Name = p.C21Name,
Server = p.Server,
Port = p.Port,
Connection = p.Connection
})
.ToList();
return
pays;
}
public
IEnumerable<Permission> ReadPerm(Int32 uid, Int32 pid)
{
var viewModel =
new
PayrollIndexData();
var selectedPay = viewModel.Payrolls.Where(x => x.PayrollID == pid).Single();
var usersPay = selectedPay.Permissions.Where(u => u.UserID == uid);
viewModel.Permissions = usersPay;
var perms = viewModel.Permissions;
return
perms;
}
/// <summary>
/// Creates new products by inserting the data posted by the Kendo Grid in the database.
/// </summary>
/// <param name="products">The products created by the user.</param>
/// <returns>The inserted products so the Kendo Grid is aware of the database generated ProductID</returns>
[HttpPost]
public
ActionResult Create(IEnumerable<User> _users)
{
var result =
new
List<User>();
//Iterate all created products which are posted by the Kendo Grid
foreach
(var user
in
_users)
{
// Create a new Product entity and set its properties from productViewModel
var _user =
new
User
{
NetLogin = user.NetLogin,
EmpNumber = user.EmpNumber,
Forename = user.Forename,
Surname = user.Surname,
Active = user.Active
};
// store the product in the result
result.Add(_user);
// Add the entity
unitOfWork.UserRepository.Insert(_user);
}
// Insert all created products to the database
unitOfWork.Save();
// Return the inserted products - the Kendo Grid needs their ProductID which is generated by SQL server during insertion
return
Json(result.Select(p =>
new
User
{
UserID = p.UserID,
NetLogin = p.NetLogin,
EmpNumber = p.EmpNumber,
Forename = p.Forename,
Surname = p.Surname,
Active = p.Active
})
.ToList());
}
/// <summary>
/// Reads the available products to provide data for the Kendo Grid
/// </summary>
/// <returns>All available products as JSON</returns>
[HttpPost]
public
ActionResult Read()
{
var _users = unitOfWork.UserRepository.Get()
// Use a view model to avoid serializing internal Entity Framework properties as JSON
.Select(p =>
new
User
{
UserID = p.UserID,
NetLogin = p.NetLogin,
EmpNumber = p.EmpNumber,
Forename = p.Forename,
Surname = p.Surname,
Active = p.Active
})
.ToList();
return
Json(_users);
}
/// <summary>
/// Updates existing products by updating the database with the data posted by the Kendo Grid.
/// </summary>
/// <param name="products">The products updated by the user</param>
[HttpPost]
public
ActionResult Update(IEnumerable<User> _users)
{
//Iterate all created products which are posted by the Kendo Grid
foreach
(var user
in
_users)
{
// Attach the entity
unitOfWork.UserRepository.Update(user);
}
// Save all updated products to the database
unitOfWork.Save();
//Return emtpy result
return
Json(
null
);
}
/// <summary>
/// Destroys existing products by deleting them from the database.
/// </summary>
/// <param name="products">The products deleted by the user</param>
[HttpPost]
public
ActionResult Destroy(IEnumerable<User> _users)
{
//Iterate all destroyed products which are posted by the Kendo Grid
foreach
(var user
in
_users)
{
// Delete the entity
unitOfWork.UserRepository.Delete(user);
}
// Delete the products from the database
unitOfWork.Save();
//Return emtpy result
return
Json(
null
);
}
//
// GET: /User/Details/5
public
ViewResult Details(Int32? id, Int32? payrollID, IEnumerable<User> _users)
{
var viewModel =
new
PayrollIndexData();
foreach
(var _user
in
_users)
{
viewModel.Users = unitOfWork.UserRepository.Get(i => i.UserID == _user.UserID);
}
if
(id !=
null
)
{
ViewBag.UserID = id.Value;
viewModel.Payrolls = unitOfWork.UserRepository.Get(i => i.UserID == id.Value).Single().Permissions.Select(p => p.Payroll).Distinct();
}
if
(payrollID !=
null
)
{
ViewBag.PayrollID = payrollID.Value;
var selectedPayroll = viewModel.Payrolls.Where(x => x.PayrollID == payrollID).Single();
var usersPayroll = selectedPayroll.Permissions.Where(u => u.UserID == id.Value);
viewModel.Permissions = usersPayroll;
}
return
View(viewModel);
}
protected
override
void
Dispose(
bool
disposing)
{
unitOfWork.Dispose();
base
.Dispose(disposing);
}
}
}
This is my view so far, again the second grid code and the selectable: true in the first grid are my attempts to get this to work:
@section CustomHeader {
@* kendo.common.min.css contains common CSS rules used by all Kendo themes *@
<
link
href
=
"http://cdn.kendostatic.com/2012.2.710/styles/kendo.common.min.css"
rel
=
"stylesheet"
/>
@* kendo.silver.min.css contains the "Blue Opal" Kendo theme *@
<
link
href
=
"http://cdn.kendostatic.com/2012.2.710/styles/kendo.silver.min.css"
rel
=
"stylesheet"
/>
<
script
src
=
"http://cdn.kendostatic.com/2012.2.710/js/kendo.all.min.js"
></
script
>
}
<
h2
>Users</
h2
>
@* The DIV where the Kendo grid will be initialized *@
<
div
id
=
"grid"
></
div
>
<
script
>
$(function () {
$("#grid").kendoGrid({
height: 425,
selectable: "true",
columns: [
{ field: "NetLogin", width: "60px" },
{ field: "EmpNumber", width: "60px" },
{ field: "Forename", width: "90px" },
{ field: "Surname", width: "90px" },
{ field: "Active", width: "45px" },
{ command: "destroy", title: "Command", width: "120px", groupable: false, filterable: false }
],
change: function() {
var row = this.select();
var id = row.data("id");
$("#log").html("selected row with id= " + id);
var secondGrid = $("#grid2").data("kendoGrid");
var row = secondGrid.table.find('tr[data-id="' + id + '"]');
secondGrid.select(row);
},
editable: true, // enable editing
sortable: true,
pageable: true,
filterable: true,
groupable: true,
resizable: true,
reorderable: true,
toolbar: ["create", "save", "cancel"], // specify toolbar commands
dataSource: {
pageSize: 20,
schema: {
model: { // define the model of the data source. Required for validation and property types.
id: "UserID",
fields: {
UserID: { editable: false, nullable: true },
NetLogin: { validation: { required: true } },
EmpNumber: { validation: { required: true } },
Forename: { validation: { required: true } },
Surname: { validation: { required: true } },
Active: { validation: { required: false } }
}
}
},
batch: true, // enable batch editing - changes will be saved when the user clicks the "Save changes" button
transport: {
create: {
url: "@Url.Action("Create", "User")", //specify the URL which should create new records. This is the Create method of the HomeController.
type: "POST" //use HTTP POST request as the default GET is not allowed for ASMX
},
read: {
url: "@Url.Action("Read", "User")", //specify the URL which should return the records. This is the Read method of the HomeController.
type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
},
update: {
url:"@Url.Action("Update", "User")", //specify the URL which should update the records. This is the Update method of the HomeController.
type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
},
destroy: {
url: "@Url.Action("Destroy", "User")", //specify the URL which should destroy the records. This is the Destroy method of the HomeController.
type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
},
parameterMap: function(data, operation) {
if (operation != "read") {
// post the products so the ASP.NET DefaultModelBinder will understand them:
// _users[0].Value="value"
// _users[0].UserID =1
// _users[1].Value="value"
// _users[1].UserID =1
var result = {};
for (var i = 0; i <
data.models.length
; i++) {
var
_user
=
data
.models[i];
for (var member in _user) {
result["_users[" + i + "]." + member] = _user[member];
}
}
return result;
}
}
}
}
});
});
</script>
<
h2
>Payrolls</
h2
>
@* The DIV where the Kendo grid will be initialized *@
<
div
id
=
"grid2"
></
div
>
<
script
>
$(function () {
$("#grid2").kendoGrid({
height: 425,
columns: [
{ field: "PayrollID", width: "45px" },
{ field: "Title", width: "100px" },
{ field: "C21Name", width: "70px" },
{ field: "Server", width: "70px" },
{ field: "Port", width: "30px" },
{ field: "Connection", width: "130px" }
],
sortable: true,
pageable: true,
filterable: true,
groupable: true,
resizable: true,
reorderable: true,
dataSource: {
pageSize: 20,
schema: {
model: { // define the model of the data source. Required for validation and property types.
id: "PayrollID",
fields: {
PayrollID: { editable: false, nullable: true },
Title: { validation: { required: true} },
C21Name: { validation: { required: true} },
Server: { validation: { required: true} },
Port: { validation: { required: true} },
Connection: { validation: { required: true} }
}
}
},
parameterMap: function (data, operation) {
if (operation != "read") {
// post the products so the ASP.NET DefaultModelBinder will understand them:
// agrps[0].Value="value"
// agrps[0].PayrollID =1
// agrps[1].Value="value"
// agrps[1].PayrollID =1
var result = {};
for (var i = 0; i <
data.models.length
; i++) {
var
pay
=
data
.models[i];
for (var member in pay) {
result["pays[" + i + "]." + member] = pay[member];
}
}
return result;
}
}
}
});
});
</script>
Your help will be greatly appreciated!
Andy