Grid inline editing demo


Inline editing for grid achieved using InlineEdit grid mod
Delete action is the same as in the grid crud demo, using a popup.
To set initial values on create set the initial model as a parameter in the inlineCreate method, example: $grid.data('api').inlineCreate({ Name: 'hi' })
On Save you also get the grid parameters, for example this grid has txtSearchInl as parent, so you get the value of txtSearchInl as 'search' parameter in the Edit/Create post actions
Shared/Demos/GridInlineCrud.cshtml
@{
var gridId = "DinnersInlineCrudGrid";
var initObj = new
{
Name = DemoUtils.RndName(),
Date = DateTime.Now.ToShortDateString(),
ChefId = Db.Chefs.First().Id,
MealsIds = Db.Meals.Take(2).Select(o => o.Id).ToArray()
};
}
<div class="bar">
<div style="float: right;">
@Html.Awe().TextBox("txtSearchInl").Placeholder("search...").CssClass("searchtxt")
</div>
<button type="button" onclick="$('#@gridId').data('api').inlineCreate()" class="awe-btn">Create</button>

@Html.InlineCreateButtonForGrid(gridId, initObj, "Create with predefined values")
</div>

@Html.InitDeletePopupForGrid(gridId, "GridInlineEditDemo")

@(Html.Awe().Grid(gridId)
.Mod(o => o.Main(false)
.InlineEdit(Url.Action("Save", "GridInlineEditDemo"))) //, reloadOnSave:true, oneRow:true
.Url(Url.Action("GridGetItems", "GridInlineEditDemo"))
.Parent("txtSearchInl", "search")
.Height(350)
.Resizable()
.Reorderable()
.Attr("data-syncg", "dinner") // crud sync using signalr in site.js
.Columns(
new Column { Bind = "Id", Width = 75 }
.Mod(o => o.InlineId()),

new Column { Bind = "Name" }
.Mod(o => o.Inline(Html.Awe().TextBox("Name"))),

new Column { Bind = "Date", Width = 180 }
.Mod(o => o.Inline(Html.Awe().DatePicker("Date").ReadonlyInput().ChangeYear().ChangeMonth())),

new Column { Bind = "Chef.FirstName,Chef.LastName", ClientFormat = ".(ChefName)", Header = "Chef", MinWidth = 170 }
.Mod(o => o.Inline(Html.Awe().Lookup("Chef").Controller("ChefLookup"), "ChefId")),

new Column { ClientFormat = ".(Meals)", Header = "Meals", MinWidth = 200, Grow = 2.2 }
.Mod(o => o.Inline(
Html.Awe().AjaxCheckboxList("Meals")
.Url(Url.Action("GetMealsImg", "Data"))
.Multiselect(d => d.ItemFunc("site.imgItem").CaptionFunc("utils.imgCaption")), "MealsIds")),

new Column { Bind = "BonusMeal.Name", ClientFormat = ".(BonusMeal)", Header = "Bonus Meal" }
.Mod(o => o.Inline(
Html.Awe().AjaxRadioList("BonusMealId")
.Url(Url.Action("GetMealsImg", "Data"))
.Odropdown(d => d.ItemFunc("site.imgItem").CaptionFunc("utils.imgCaption")), "BonusMealId")),

new Column { Bind = "Organic", Width = 90, ClientFormat = ".(DispOrganic)" }
.Mod(o => o.Inline(Html.Awe().CheckBox("Organic").Otoggl())),

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

@*grid client validation (for MVC5 must be placed in a cshtml with @model DinnerInput)*@
@(Html.BindOVld<DinnerInput>("#" + gridId))
Demos/Grid/GridInlineEditDemoController.cs
public class GridInlineEditDemoController : Controller
{
public IActionResult Index()
{
return View();
}

public IActionResult ConditionalDemo()
{
return View();
}

public IActionResult MultiEditorsDemo()
{
return View();
}

public IActionResult ClientSave()
{
return View();
}


private object MapToGridModel(Dinner o)
{
return new
{
o.Id,
o.Name,
Date = o.Date.ToShortDateString(),
ChefName = o.Chef.FirstName + " " + o.Chef.LastName,
Meals = string.Join(", ", o.Meals.Select(m => m.Name)),
BonusMeal = o.BonusMeal.Name,
o.Organic,
DispOrganic = o.Organic ? "Yes" : "No",

// below properties used for inline editing only
MealsIds = o.Meals.Select(m => m.Id).ToArray(),
ChefId = o.Chef.Id,
BonusMealId = o.BonusMeal.Id,

// for conditional demo
Editable = o.Meals.Count() > 1,
DateReadOnly = o.Date.Year < 2015
};
}

public IActionResult GridGetItems(GridParams g, string search)
{
search = (search ?? "").ToLower();
var items = Db.Dinners.Where(o => o.Name.ToLower().Contains(search)).AsQueryable();

var model = new GridModelBuilder<Dinner>(items, g)
{
KeyProp = o => o.Id, // needed for api select, update, tree, nesting, EF
GetItem = () => Db.Get<Dinner>(Convert.ToInt32(g.Key)), // called by the grid.api.update
Map = MapToGridModel,
}.Build();

return Json(model);
}

[HttpPost]
public IActionResult Save(DinnerInput input)
{
if (ModelState.IsValid)
{
var edit = input.Id.HasValue;
var ent = edit ? Db.Get<Dinner>(input.Id) : new Dinner();

ent.Name = input.Name;
ent.Date = input.Date.Value;
ent.Chef = Db.Get<Chef>(input.Chef);
ent.Meals = input.Meals.Select(mid => Db.Get<Meal>(mid));
ent.BonusMeal = Db.Get<Meal>(input.BonusMealId);
ent.Organic = input.Organic ?? false;

if (edit)
{
Db.Update(ent);
}
else
{
Db.Insert(ent);
}

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

return Json(ModelState.GetErrorsInline());
}

public IActionResult Delete(int id)
{
var dinner = Db.Get<Dinner>(id);

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

[HttpPost]
public IActionResult Delete(DeleteConfirmInput input)
{
Db.Delete<Dinner>(input.Id);

// the PopupForm's success function utils.itemDeleted expects an obj with "Id" property
return Json(new { input.Id });
}

public IActionResult Popup()
{
return PartialView();
}
}

Edit on row click


Edit on row click, and save when clicking out if there is are any changes.
In case of validation errors grid loading (go to another page, sort, group) will be prevented.
GridInlineEditDemo/Index.cshtml
@{ var grid2Id = "DinnersGrid2"; }
<div class="bar">
<div style="float: right;">
@Html.Awe().TextBox("txtSearch2").Placeholder("search...").CssClass("searchtxt")
</div>
<button type="button" onclick="$('#@grid2Id').data('api').inlineCreate()" class="awe-btn">Create</button>
</div>

@Html.InitDeletePopupForGrid(grid2Id, "GridInlineEditDemo")

@(Html.Awe().Grid(grid2Id)
.Mod(o => o.Main(false).InlineEdit(Url.Action("Save"), rowClickEdit: true))
.Url(Url.Action("GridGetItems"))
.Parent("txtSearch2", "search")
.Height(350)
.Resizable()
.Reorderable()
.Attr("data-syncg", "dinner")
.Columns(
new Column { Bind = "Id", Width = 75 }
.Mod(o => o.InlineId()),

new Column { Bind = "Name" }
//.Mod(o => o.Inline(Html.Awe().TextBox("Name"))), // simple textbox
.Mod(o => o.Inline(
Html.Awe().Autocomplete("Name")
.Url(Url.Action("GetMealsImg", "Data")))),

new Column { Bind = "Date", Width = 160 }
.Mod(o => o.Inline(Html.Awe().DatePicker("Date").ReadonlyInput().ChangeYear().ChangeMonth())),

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

new Column { ClientFormat = ".(Meals)", Header = "Meals", MinWidth = 250 }
.Mod(o => o.Inline(
Html.Awe().AjaxCheckboxList("Meals")
.Multiselect()
.Url(Url.Action("GetMealsImg", "Data")), "MealsIds")),

new Column { Bind = "BonusMeal.Name", ClientFormat = ".(BonusMeal)", Header = "Bonus Meal" }
.Mod(o => o.Inline(
Html.Awe().Odropdown("BonusMealId")
.Url(Url.Action("GetMealsImg", "Data")), "BonusMealId")),

new Column { Bind = "Organic", Width = 90, ClientFormat = ".(DispOrganic)" }
.Mod(o => o.Inline(Html.Awe().CheckBox("Organic").Otoggl())),

new Column { ClientFormat = GridUtils.InlineEditFormat(), Width = 80 },
new Column { ClientFormat = Html.InlineDeleteFormatForGrid(grid2Id), Width = 85 }))

@*grid client validation (for MVC5 must be placed in a cshtml with @model DinnerInput)*@
@(Html.BindOVld<DinnerInput>("#" + grid2Id))



Comments