Awesome ASP.net Core and MVC Controls

Master Detail CRUD Demo using Grid and PopupForm

This is a demo for master detail CRUD using the Grid.
For master-detail grid see Master Detail Grid, or Hierarchy (Nested Grids)
MasterDetailCrudDemo/Index.cshtml
@{ var grid1 = "RestaurantGrid"; }
@Html.InitCrudPopupsForGrid(grid1, "MasterDetailCrudDemo", 470, 1000)

<div class="bar">
@Html.CreateButtonForGrid(grid1)
</div>

@(Html.Awe().Grid(grid1)
.Height(350)
.Attr("data-syncg", "rest") // crud sync using signalr in site.js
.Url(Url.Action("RestaurantGridGetItems"))
.Groupable(false)
.Columns(
new Column { ClientFormat = ".(Id)", Header = "Id", Width = 70 },
new Column { Bind = "Name" },
new Column { ClientFormat = GridUtils.EditFormatForGrid(grid1), Width = 55 },
new Column { ClientFormat = GridUtils.DeleteFormatForGrid(grid1), Width = 55 }))
MasterDetailCrudDemo/Create.cshtml
@model AwesomeMvcDemo.ViewModels.Input.RestaurantInput
@using (Html.Awe().BeginContext())
{
var gridId = "AddressesGrid";
using (Html.BeginForm())
{
@Html.EditorFor(o => o.Id)
@Html.EditorFor(o => o.Name)
}

@Html.InitCrudPopupsForGrid(gridId, "AddressesGridCrud", 230)

<div class="bar">
@Html.CreateButtonForGrid(gridId, new { restaurantId = Model.Id}, "Add address")
</div>
<div>
@(Html.Awe().Grid(gridId).Url(Url.Action("GridGetItems", "AddressesGridCrud"))
.Parameter("restaurantId", Model.Id)
.Attr("data-syncg","addr")
.Height(230)
.Groupable(false)
.Columns(
new Column { Bind = "Line1,Line2", ClientFormat = ".(Line1) .(Line2)", Header = "Address" },
new Column { Bind = "Chef.FirstName,Chef.LastName", ClientFormat = ".(ChefName)", Header = "Chef" },
new Column { ClientFormat = Html.EditFormatForGrid(gridId), Width = 52 },
new Column { ClientFormat = Html.DeleteFormatForGrid(gridId), Width = 52 }))
</div>
}
AddressesGridCrud/Create.cshtml
@model AwesomeMvcDemo.ViewModels.Input.RestaurantAddressInput

@using (Html.BeginForm())
{
@Html.EditorFor(o => o.RestaurantId)
@Html.EditorFor(o => o.Line1)
@Html.EditorFor(o => o.Line2)
@Html.EditorFor(o => o.ChefId)
}
Demos/Grid/MasterDetailCrud/MasterDetailCrudDemoController.cs
public class MasterDetailCrudDemoController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult RestaurantGridGetItems(GridParams g)
{
var model = new GridModelBuilder<Restaurant>(Db.Restaurants.Where(o => o.IsCreated).AsQueryable(), g)
{
Key = "Id",
GetItem = () => Db.Get<Restaurant>(Convert.ToInt32(g.Key))
}.Build();
return Json(model);
}

public ActionResult Create()
{
// needed so we could add addresses even before the restaurant is created/saved
var rest = Db.Insert(new Restaurant());

return PartialView(new RestaurantInput { Id = rest.Id });
}

[HttpPost]
public ActionResult Create(RestaurantInput input)
{
if (!ModelState.IsValid)
{
return PartialView(input);
}

var restaurant = Db.Get<Restaurant>(input.Id);
restaurant.Name = input.Name;
restaurant.IsCreated = true;

return Json(restaurant); // use MapToGridModel like in Grid Crud Demo when grid uses Map
}

public ActionResult Edit(int id)
{
var rest = Db.Get<Restaurant>(id);
return PartialView("Create", new RestaurantInput { Id = id, Name = rest.Name });
}

[HttpPost]
public ActionResult Edit(RestaurantInput input)
{
if (!ModelState.IsValid)
{
return PartialView("Create", input);
}

var rest = Db.Get<Restaurant>(Convert.ToInt32(input.Id));

rest.Name = input.Name;

return Json(new { rest.Id });
}

public ActionResult Delete(int id, string gridId)
{
var restaurant = Db.Get<Restaurant>(id);

return PartialView(new DeleteConfirmInput
{
Id = id,
Type = "restaurant",
Name = restaurant.Name
});
}

[HttpPost]
public ActionResult Delete(DeleteConfirmInput input)
{
Db.Delete<Restaurant>(input.Id);
return Json(new { input.Id });
}
}
Demos/Grid/MasterDetailCrud/AddressesGridCrudController.cs
public class AddressesGridCrudController : Controller
{
public ActionResult GridGetItems(GridParams g, int restaurantId)
{
var items = Db.RestaurantAddresses.Where(o => o.RestaurantId == restaurantId).AsQueryable();
var model = new GridModelBuilder<RestaurantAddress>(items, g)
{
Key = "Id",
Map = o => new
{
o.Id,
o.Line1,
o.Line2,
ChefName = o.Chef.FirstName + " " + o.Chef.LastName
},
GetItem = () => Db.Get<RestaurantAddress>(Convert.ToInt32(g.Key))
}.Build();
return Json(model);
}

public ActionResult Create(int restaurantId)
{
return PartialView(new RestaurantAddressInput { RestaurantId = restaurantId });
}

[HttpPost]
public ActionResult Create(RestaurantAddressInput input)
{
if (!ModelState.IsValid)
{
return PartialView(input);
}

var address = Db.Insert(new RestaurantAddress { Line1 = input.Line1, Line2 = input.Line2, RestaurantId = input.RestaurantId });

return Json(address); // use MapToGridModel like in Grid Crud Demo when grid uses Map
}

public ActionResult Edit(int id)
{
var address = Db.Get<RestaurantAddress>(id);

return PartialView(
"Create",
new RestaurantAddressInput
{
Line1 = address.Line1,
Line2 = address.Line2,
ChefId = address.Chef.Id,
RestaurantId = address.RestaurantId
});
}

[HttpPost]
public ActionResult Edit(RestaurantAddressInput input)
{
if (!ModelState.IsValid)
{
return PartialView("Create", input);
}

var address = Db.Get<RestaurantAddress>(input.Id);
address.Line1 = input.Line1;
address.Line2 = input.Line2;
address.Chef = Db.Get<Chef>(input.ChefId);

return Json(new { input.Id });
}

public ActionResult Delete(int id)
{
var address = Db.Get<RestaurantAddress>(id);

return PartialView(new DeleteConfirmInput
{
Id = id,
Type = "restaurant address",
Name = address.Line1 + " "+ address.Line2
});
}

[HttpPost]
public ActionResult Delete(DeleteConfirmInput input)
{
Db.Delete<RestaurantAddress>(input.Id);
return Json(new { input.Id });
}
}

Inline editing inside details popup

MasterDetailCrudDemo/Index.cshtml
@{ var gridIE = "RestaurantGridIE1"; }
@Html.InitCrudPopupsForGrid(gridIE, "MasterDetailInline", 470, 1000)

<div class="bar">
@Html.CreateButtonForGrid(gridIE)
</div>

@(Html.Awe().Grid(gridIE)
.Height(350)
.Attr("data-syncg", "rest") // crud sync using signalr in site.js
.Url(Url.Action("RestaurantGridGetItems"))
.Groupable(false)
.Columns(
new Column { ClientFormat = ".(Id)", Header = "Id", Width = 70 },
new Column { Bind = "Name" },
new Column { ClientFormat = GridUtils.EditFormatForGrid(gridIE), Width = 55 },
new Column { ClientFormat = GridUtils.DeleteFormatForGrid(gridIE), Width = 55 }))
MasterDetailInline/Create.cshtml
@model AwesomeMvcDemo.ViewModels.Input.RestaurantInput
@using (Html.Awe().BeginContext())
{
var gridId = "AddressesGrid";
using (Html.BeginForm())
{
@Html.EditorFor(o => o.Id)
@Html.EditorFor(o => o.Name)
}

<div class="bar">
@Html.InlineCreateButtonForGrid(gridId, new { restaurantId = Model.Id }, "Add address")
</div>
<div>
@(Html.Awe().Grid(gridId)
.Url(Url.Action("AddressGrid", "MasterDetailInline"))
.Mod(o => o.InlineEdit(Url.Action("CreateAddr"), Url.Action("EditAddr"), rowClickEdit: true))
.Parameter("restaurantId", Model.Id)
.Attr("data-syncg", "addr")
.Height(230)
.Groupable(false)
.Columns(
new Column { Bind = "Id", Width = 75 }
.Mod(o => o.InlineId()),

new Column { Bind = "Line1,Line2", ClientFormat = ".(Line1) .(Line2)", Header = "Address" }
.Mod(o => o.Inline(Html.Awe().TextBox("Line1"))
.Inline(Html.Awe().TextBox("Line2"))),

new Column { Bind = "Chef.FirstName,Chef.LastName", ClientFormat = ".(ChefName)", Header = "Chef" }
.Mod(o => o.Inline(Html.Awe().AjaxRadioList("ChefId")
.Url(Url.Action("GetChefs", "Data"))
.Odropdown())),

new Column { ClientFormat = GridUtils.InlineEditFormat(), Width = 80 },
new Column { ClientFormat = Html.InlineDeleteFormatForGrid(gridId), Width = 85 }))
</div>
}

Master Detail CRUD using in nest editing

MasterDetailCrudDemo/Index.cshtml
@{ var grid2 = "RestaurantGrid2"; }
@Html.InitCrudForGridNest(grid2, "MasterDetailCrudDemo")

<div class="bar">
<button type="button" onclick="utils.nestCreate('@grid2', 'create@(grid2)')" class="awe-btn mbtn">Create</button>
</div>

@(Html.Awe().Grid(grid2)
.Url(Url.Action("RestaurantGridGetItems"))
.PageSize(10)
.Attr("data-syncg", "rest")
.Nests(
new Nest { Name = "editnst", GetFunc = "utils.loadNestPopup('edit" + grid2 + "')" },
new Nest { Name = "delnst", GetFunc = "utils.loadNestPopup('delete" + grid2 + "')" })
.Columns(
new Column { ClientFormat = ".Id", Header = "Id", Width = 70 },
new Column { Bind = "Name" },
new Column { ClientFormat = GridUtils.EditGridNestFormat(), Width = 55 },
new Column { ClientFormat = GridUtils.DeleteGridNestFormat(), Width = 55 }))

Master Detail CRUD using Inline Editing and nesting

MasterDetailCrudDemo/Index.cshtml
@{
var grid3 = "RestaurantGridInline";
}

@Html.InitDeletePopupForGrid(grid3)

<div class="bar">
@Html.Awe().Button().Text("Create").OnClick("$('#" + grid3 + "').data('api').inlineCreate()").CssClass("mbtn")
</div>

@(Html.Awe().Grid(grid3)
.Url(Url.Action("RestaurantGridGetItems"))
.Mod(o => o.InlineEdit(Url.Action("Create", "RestInl"), Url.Action("Edit", "RestInl"), rowClickEdit: true))
.Groupable(false)
.Attr("data-syncg", "rest")
.Nests(new Nest { Name = "detailnst", Url = Url.Action("Addresses", "RestInl"), LoadOnce = true })
.Columns(
new Column { ClientFormat = ".Id", Header = "Id", Width = 70 }.Mod(o => o.InlineId()),
new Column { Bind = "Name" }.Mod(o => o.Inline(Html.Awe().TextBox("Name"))),
new Column
{
ClientFormat = "<button type='button' class='awe-btn o-pad detailnst'>details <i class='caretc'><i class='o-caret'></i></i></button>",
Width = 105
},
new Column { ClientFormat = GridUtils.InlineEditFormat(), Width = 80 },
new Column { ClientFormat = Html.InlineDeleteFormatForGrid(grid3), Width = 90 }))
<style>
/* hide addresses button for new rows */
.o-glnew .detailnst {
display: none;
}

.caretc {
position: relative;
padding: .4em .5em;
display: inline-block;
}

.caretc .o-caret {
transform: rotate(-90deg);
zoom: 1.1;
}

.detailnst-on .caretc .o-caret {
transform: rotate(0);
}
</style>
RestInl/Addresses.cshtml
@{
var restId = ViewData["Id"];
var gridId = "AddrGrid-" + restId;
}

@Html.InitDeletePopupForGrid(gridId, "AddressesGridCrud")

<div style="padding: .5em;">
<div class="bar">
<button type="button" class="awe-btn mbtn" onclick="$('#@gridId').data('api').inlineCreate()">Create</button>
</div>
@(Html.Awe().Grid(gridId)
.Url(Url.Action("GridGetItems", "AddressesGridCrud"))
.Mod(o => o.InlineEdit(Url.Action("Create", "AddrInlGrid"), Url.Action("Edit", "AddrInlGrid"), rowClickEdit:true))
.Parameter("restaurantId", restId)
.Attr("data-syncg", "addr")
.Height(200)
.Groupable(false)
.Columns(
new Column { Bind = "Id", Hidden = true }.Mod(o => o.InlineReadonly()),
new Column { Bind = "Line1", ClientFormat = ".(Line1)", Header = "Line 1" }
.Mod(o => o.Inline(Html.Awe().TextBox("Line1"))),
new Column { Bind = "Line2", ClientFormat = ".(Line2)", Header = "Line 2" }
.Mod(o => o.Inline(Html.Awe().TextBox("Line2"))),
new Column { ClientFormat = GridUtils.InlineEditFormat(), Width = 80 },
new Column { ClientFormat = Html.InlineDeleteFormatForGrid(gridId), Width = 80 }))
</div>
Demos/Grid/MasterDetailCrud/RestInlController.cs
public class RestInlController : Controller
{
public ActionResult Addresses(int key)
{
ViewData["Id"] = key;
return PartialView();
}

private object MapToGridModel(Restaurant o)
{
return new { o.Id, o.Name };
}

[HttpPost]
public ActionResult Create(RestaurantInput input)
{
if (!ModelState.IsValid)
{
return Json(ModelState.GetErrorsInline());
}

var ent = Db.Insert(new Restaurant
{
Name = input.Name,
IsCreated = true
});

return Json(new { Item = MapToGridModel(ent) });

}

[HttpPost]
public ActionResult Edit(RestaurantInput input)
{
if (!ModelState.IsValid)
{
return Json(ModelState.GetErrorsInline());
}

var ent = Db.Get<Restaurant>(input.Id);
ent.Name = input.Name;
Db.Update(ent);

return Json(new { });
}
}



Comments

We use cookies to improve your online experience. By accessing this site, you agree to the use of cookies and other technologies to process your personal data (e.g. IP address) to enhance and personalise your experience across our websites. Additionally, third-party companies, may store cookies on your device and use similar technologies to collect and use certain information. For more information, refer to our privacy policy and cookie policy.