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.aspx
<%  var grid1 = RestaurantGrid.ClientID;  %>
<%=Page.InitCrudPopupsForGrid(grid1, "MasterDetailCrudDemo", 470, 1000) %>

<div class="bar">
<button type="button" class="awe-btn mbtn" onclick="awe.open('create<%=grid1 %>')">Create</button>
</div>

<% RestaurantGrid.Grid()
.Height(350)
.Attr("data-syncg", "rest") // crud sync using signalr in site.js
.Url(Page.Url().Action("RestaurantGridGetItems", "MasterDetailCrudDemo"))
.Groupable(false)
.Columns(
new Column { ClientFormat = ".(Id)", Header = "Id", Width = 70 },
new Column { Bind = "Name" },
Page.EditColumnForGrid(grid1),
Page.DeleteColumnForGrid(grid1)); %>
<awe:Ocon runat="server" ID="RestaurantGrid" />
\Views\MasterDetailCrudDemo/Create.cshtml
@model AwesomeWebFormsDemo.ViewModels.Input.RestaurantInput
@using (Html.Awe().BeginContext())
{
var gridId = "AddressesGrid";
using (Html.BeginForm())
{
<div class="eform">
<div class="earea">
@Html.EditorFor(o => o.Id)
@Html.EditorFor(o => o.Name)
</div>
</div>
}

@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", Prop = "ChefName", Header = "Chef" },
Html.EditColumnForGrid(gridId),
Html.DeleteColumnForGrid(gridId)))
</div>
}
\Views\AddressesGridCrud/Create.cshtml
@model AwesomeWebFormsDemo.ViewModels.Input.RestaurantAddressInput

@using (Html.Awe().BeginContext())
{
using (Html.BeginForm())
{
<div class="eform">
<div class="earea">
@Html.EditorFor(o => o.RestaurantId)
@Html.EditorFor(o => o.Line1)
@Html.EditorFor(o => o.Line2)
@Html.EditorFor(o => o.ChefId)
</div>
</div>
}
}
Demos/Grid/MasterDetailCrud/MasterDetailCrudDemoController.cs
using System;
using System.Linq;
using AwesomeWebFormsDemo.Data;
using AwesomeWebFormsDemo.Models;
using AwesomeWebFormsDemo.ViewModels.Input;
using System.Web.Mvc;

using Omu.AwesomeWebForms;

namespace AwesomeWebFormsDemo.Controllers.Demos.Grid.MasterDetailCrud
{
public class MasterDetailCrudDemoController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult RestaurantGridGetItems(GridParams g)
{
var query = Db.Restaurants.Where(o => o.IsCreated).AsQueryable();

var gmb = new GridModelBuilder<Restaurant>(query, g)
{
KeyProp = o => o.Id,
GetItem = () => Db.Get<Restaurant>(Convert.ToInt32(g.Key))
};

return this.AweJson(gmb.Build());
}

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

Db.Add(rest);


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

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

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



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

public ActionResult Edit(int id)
{
var rest = Db.Find<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.Find<Restaurant>(input.Id);

rest.Name = input.Name;

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

public ActionResult Delete(int id)
{
var restaurant = Db.Find<Restaurant>(id);

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

[HttpPost]
public ActionResult Delete(DeleteConfirmInput input)
{
Db.Remove(Db.Find<Restaurant>(input.Id));


return Json(new { input.Id });
}
}
}
Demos/Grid/MasterDetailCrud/AddressesGridCrudController.cs
using System;
using System.Linq;
using AwesomeWebFormsDemo.Data;
using AwesomeWebFormsDemo.Models;
using AwesomeWebFormsDemo.ViewModels.Input;
using System.Web.Mvc;

using Omu.AwemWebForms.Utils;
using Omu.AwesomeWebForms;

namespace AwesomeWebFormsDemo.Controllers.Demos.Grid.MasterDetailCrud
{
public class AddressesGridCrudController : Controller
{
private object mapToGridModel(RestaurantAddress o)
{
return new
{
o.Id,
o.Line1,
o.Line2,
ChefName = o.Chef.FullName,

ChefId = o.Chef.Id // for inline editing, value to the Chef inline dropdown
};
}

public ActionResult GridGetItems(GridParams g, int restaurantId)
{
var query = Db.RestaurantAddresses
.Where(o => o.RestaurantId == restaurantId)
.AsQueryable();

var gmb = new GridModelBuilder<RestaurantAddress>(query, g)
{
KeyProp = o => o.Id,
Map = mapToGridModel,
};

return this.AweJson(gmb.Build());
}

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 = new RestaurantAddress
{
Line1 = input.Line1,
Line2 = input.Line2,
RestaurantId = input.RestaurantId,
Chef = Db.Find<Chef>(input.ChefId)
};

Db.Add(address);



return Json(mapToGridModel(address));
}

public ActionResult Edit(int id)
{
var address = Db.RestaurantAddresses
.First<RestaurantAddress>(o => o.Id == 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.Find<RestaurantAddress>(input.Id);
address.Line1 = input.Line1;
address.Line2 = input.Line2;
address.Chef = Db.Find<Chef>(input.ChefId);


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

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

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

[HttpPost]
public ActionResult Delete(DeleteConfirmInput input)
{
Db.Remove(Db.Find<RestaurantAddress>(input.Id));



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

#region for inline editing
[HttpPost]
public ActionResult CreateInline(RestaurantAddressInput input)
{
if (!ModelState.IsValid)
{
return Json(ModelState.GetErrorsInline());
}

var ent = new RestaurantAddress
{
RestaurantId = input.RestaurantId,
Line1 = input.Line1,
Line2 = input.Line2,
Chef = Db.Find<Chef>(input.ChefId)
};

Db.Add(ent);


return Json(new { });
}

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

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



return Json(new { });
}
#endregion
}
}

Master Detail CRUD using Inline Editing and nesting

MasterDetailCrudDemo.aspx
<% 
var grid3 = RestaurantGridInline.ClientID;
%>

<%=Page.InitDeletePopupForGrid(grid3, "MasterDetailCrudDemo") %>

<div class="bar">
<% Button1.Button().Text("Create").OnClick("$('#" + grid3 + "').data('api').inlineCreate()").CssClass("mbtn"); %>
<awe:Ocon runat="server" ID="Button1" />
</div>

<% RestaurantGridInline.Grid()
.Url(Page.Url().Action("RestaurantGridGetItems", "MasterDetailCrudDemo"))
.Mod(o => o.InlineEdit(Page.Url().Action("Create", "RestInl"), Page.Url().Action("Edit", "RestInl"), rowClickEdit: true))
.Groupable(false)
.Attr("data-syncg", "rest")
.Nests(new Nest { Name = "detailnst", Url = Page.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(Page.Awe().TextBox("Name"))),
new Column
{
ClientFormat = "<button type='button' class='awe-btn detailnst'>details <i class='caretc'><i class='o-caret'></i></i></button>",
Width = 135
},
Page.InlEditColumn(),
Page.InlDeleteColumn(grid3)); %>
<awe:Ocon runat="server" ID="RestaurantGridInline" />
<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>
\Views\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" onclick="$('#@gridId').data('api').inlineCreate()">Create</button>
</div>
@(Html.Awe().Grid(gridId)
.Attr("data-syncg", "addr")
.Parameter("restaurantId", restId)
.Height(230)
.Url(Url.Action("GridGetItems", "AddressesGridCrud"))
.InlEdit(new InlEditOpt{
SaveUrl = Url.Action("CreateInline", "AddressesGridCrud"),
EditUrl = Url.Action("EditInline", "AddressesGridCrud"),
RowClickEdit = true
})
.Groupable(false)
.Columns(
new Column { Bind = "Id", Hidden = true }
.InlReadonly(),

new Column { Bind = "Line1", ClientFormat = ".(Line1)", Header = "Address Line 1" }
.Inl(Html.Awe().TextBox("Line1")),

new Column { Bind = "Line2", ClientFormat = ".(Line2)", Header = "Address Line 2" }
.Inl(Html.Awe().TextBox("Line2")),

new Column { Bind = "Chef.FirstName,Chef.LastName", Prop = "ChefName", Header = "Chef" }
.InlDropdownList(new DropdownListOpt { Name = "ChefId", Url = Url.Action("GetChefs", "Data") }),

Html.InlEditColumn(),
Html.InlDeleteColumn(gridId)))
</div>
Demos/Grid/MasterDetailCrud/RestInlController.cs
using System;
using AwesomeWebFormsDemo.Data;
using AwesomeWebFormsDemo.Models;
using AwesomeWebFormsDemo.ViewModels.Input;
using System.Web.Mvc;

using Omu.AwemWebForms.Utils;

namespace AwesomeWebFormsDemo.Controllers.Demos.Grid.MasterDetailCrud
{
public class RestInlController : Controller
{
public ActionResult Addresses(int key)
{
ViewData["Id"] = key;
return PartialView();
}

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

var ent = new Restaurant
{
Name = input.Name,
IsCreated = true
};

Db.Add(ent);


return Json(new { });
}

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

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



return Json(new { });
}
}
}



Comments