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 = "hi there",
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 mbtn">Create</button>

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

@Html.InitDeletePopupForGrid(gridId, "GridInlineEditDemo")

@(Html.Awe().Grid(gridId)
.Mod(o => o.PageInfo().InlineEdit(Url.Action("Create", "GridInlineEditDemo"), Url.Action("Edit", "GridInlineEditDemo")))
.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"))),
.Mod(o => o.Inline(
Html.Awe().Autocomplete("Name")
.CacheKey("atcmeals") // set to share cache with all rows
//.Url(Url.Action("GetItems", "MealAutocomplete"))
.DataFunc("utils.getItems(meals)"))),

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

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

new Column { ClientFormat = ".Meals", Header = "Meals", Width = 250 }
.Mod(o => o.Inline(Html.Awe().AjaxCheckboxList("Meals").Multiselect().DataFunc("utils.getItems(meals)"), "MealsIds")),

new Column { Bind = "BonusMeal.Name", ClientFormat = ".BonusMeal", Header = "Bonus Meal" }
.Mod(o => o.Inline(Html.Awe().AjaxRadioList("BonusMealId").Odropdown().DataFunc("utils.getItems(meals)"), "BonusMealId")),

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

new Column { ClientFormat = GridUtils.InlineEditFormat(), Width = 70 },
new Column { ClientFormat = Html.InlineDeleteFormatForGrid(gridId), Width = 80 }))
Demos/Grid/GridInlineEditDemoController.cs
public class GridInlineEditDemoController : Controller
{
public ActionResult Index()
{
return View();
}

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

public ActionResult MultiEditorsDemo()
{
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" : "",

// 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 < 2012
};
}

public ActionResult 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)
{
Key = "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 ActionResult Create(DinnerInput input)
{
if (ModelState.IsValid)
{
var dinner = new Dinner
{
Name = input.Name,
Date = input.Date.Value,
Chef = Db.Get<Chef>(input.Chef),
Meals = input.Meals.Select(mid => Db.Get<Meal>(mid)),
BonusMeal = Db.Get<Meal>(input.BonusMealId),
Organic = input.Organic ?? false
};

Db.Insert(dinner);

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

return Json(ModelState.GetErrorsInline());
}

[HttpPost]
public ActionResult Edit(DinnerInput input)
{
if (ModelState.IsValid)
{
var dinner = Db.Get<Dinner>(input.Id);
dinner.Name = input.Name;
dinner.Date = input.Date.Value;
dinner.Chef = Db.Get<Chef>(input.Chef);

dinner.Meals = input.Meals.Select(mid => Db.Get<Meal>(mid));

dinner.BonusMeal = Db.Get<Meal>(input.BonusMealId);
dinner.Organic = input.Organic ?? false;
Db.Update(dinner);

return Json(new { });
}

return Json(ModelState.GetErrorsInline());
}

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

return PartialView(new DeleteConfirmInput
{
Id = id,
Message = string.Format("Are you sure you want to delete dinner <b>{0}</b> ?", dinner.Name)
});
}

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

public ActionResult 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 mbtn">Create</button>
</div>

@Html.InitDeletePopupForGrid(grid2Id, "GridInlineEditDemo")

@(Html.Awe().Grid(grid2Id)
.Mod(o => o.PageInfo().InlineEdit(Url.Action("Create"), Url.Action("Edit"), 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"))),
.Mod(o => o.Inline(
Html.Awe().Autocomplete("Name")
.CacheKey("atcmeals")
//.Url(Url.Action("GetItems", "MealAutocomplete"))
.DataFunc("utils.getItems(meals)"))),

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

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

new Column { ClientFormat = ".Meals", Header = "Meals", Width = 250 }
.Mod(o => o.Inline(Html.Awe().AjaxCheckboxList("Meals").Multiselect().DataFunc("utils.getItems(meals)"), "MealsIds")),

new Column { Bind = "BonusMeal.Name", ClientFormat = ".BonusMeal", Header = "Bonus Meal" }
.Mod(o => o.Inline(Html.Awe().AjaxRadioList("BonusMealId").Odropdown().DataFunc("utils.getItems(meals)"), "BonusMealId")),

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

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




See also:
Grid inline editing conditional demo
Grid inline multiple editors demo


Comments