Grid inline editing

The Awesome Grid supports inline editing mode. Inline editing enables you to edit the data upon a row click or edit button click, and save the changes either by clicking the save button or exiting the row in case or rowclick edit.
Rows can be saved all at once using batch save, or one by one. Editing can also be performed one row at once instead of having multiple rows in edit mode at the same time.

Achieved using the InlineEdit grid mod.
Delete action works the same way as in the Grid CRUD demo, using a popup.
To set initial values on create, pass the initial model as a parameter in the inlineCreate method.
Example: `$grid.data('api').inlineCreate({ Name: 'hi' });`
On Save, the grid also provides parameters, in this demo, txtSearchInl acts as a parent, so its value is available as the 'search' parameter in 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">

<button type="button" onclick="$('#@gridId').data('api').inlineCreate()" class="awe-btn">Create</button>

@Html.InlineCreateButtonForGrid(gridId, initObj, "Create with predefined values")
<div style="margin-left: auto;">
@Html.Awe().TextBox("txtSearchInl").Placeholder("search...").CssClass("searchtxt")
</div>
</div>

@Html.InitDeletePopupForGrid(gridId, "GridInlineEditDemo")

@(Html.Awe().Grid(gridId)
.Mod(o => o.Main(false))
.Url(Url.Action("GridGetItems", "GridInlineEditDemo"))
.InlEdit(new InlEditOpt{
SaveUrl = Url.Action("Save", "GridInlineEditDemo")
})
.Validation(type: typeof(DinnerInput))
.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 }
.InlId()
.InlVldSummary(),

new Column { Bind = "Name" }
.InlString(),

new Column { Bind = "Date", Width = 180 }
.InlDate(),

new Column { Bind = "Chef.FirstName,Chef.LastName", Prop = "ChefName", Header = "Chef", MinWidth = 170 }
.Inl(Html.Awe().Lookup("ChefId").Controller("ChefLookup")),

new Column { Prop = "Meals", Header = "Meals", MinWidth = 200, Grow = 2.2 }
.InlMultiselect(new MultiselectOpt
{
Name = "MealsIds",
Url = Url.Action("GetMealsImg", "Data")
}
.ImgItem()),

new Column { Bind = "BonusMeal.Name", Prop = "BonusMeal", Header = "Bonus Meal" }
.InlDropdownList(new DropdownListOpt
{
Name = "BonusMealId",
Url = Url.Action("GetMealsImg", "Data")
}
.ImgItem()),

new Column { Bind = "Organic", Width = 100, Prop = "DispOrganic" }
.Inl(Html.Awe().Toggle(new ToggleOpt { Name = "Organic" })),

Html.InlEditDelColumn(gridId)))
Demos/Grid/GridInlineEditDemoController.cs
public class GridInlineEditDemoController : Controller
{
private object MapToGridModel(Dinner o)
{
return new
{
o.Id,
o.Name,
Date = o.Date.ToShortDateString(),
ChefName = o.Chef.FullName,
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 = "")
{
var query = Db.Dinners.Where(o => o.Name.Contains(search)).AsQueryable();

var model = new GridModelBuilder<Dinner>(query, g)
{
KeyProp = o => o.Id, // needed for api select, update, tree, nesting, EF
Map = MapToGridModel,
GetItem = () => Db.Get<Dinner>(Convert.ToInt32(g.Key)), // used when calling api.update (signalrSync.js)
};

return Json(model.Build());
}

[HttpPost]
public IActionResult Save(DinnerInput input)
{
// custom validation example
if (ModelState.IsValid && input.Name.Contains("asdf"))
{
ModelState.AddModelError("Name", "Name can't contain asdf");
}

if (ModelState.IsValid)
{
var isCreate = !input.Id.HasValue;

var ent = isCreate ? new Dinner() :
Db.Dinners.FirstOrDefault(o => o.Id == input.Id);

if (ent == null)
{
throw new Exception("Item doesn't exist anymore, id:" + input.Id);
}

ent.Name = input.Name;
ent.Date = input.Date.Value;
ent.Chef = Db.Find<Chef>(input.ChefId);

// ToList req for EF
ent.Meals = Db.Meals
.Where(o => input.MealsIds.Contains(o.Id)).ToList();

ent.BonusMeal = Db.Find<Meal>(input.BonusMealId);
ent.Organic = input.Organic ?? false;

if (isCreate)
{
Db.Add(ent);
}

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

return Json(ModelState.GetErrorsInline());
}

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

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

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

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

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

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

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

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

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

Edit on row click


Clicking on a row initiates editing.
Changes are saved automatically when clicking outside the row.
If validation errors occur, grid interactions such as pagination, sorting, or grouping will be blocked until the errors are resolved.
GridInlineEditDemo/Index.cshtml
@{ var grid2Id = "DinnersGrid2"; }
<div class="bar">
<button type="button" onclick="$('#@grid2Id').data('api').inlineCreate()" class="awe-btn">Create</button>
<div style="margin-left: auto;">
@Html.Awe().TextBox("txtSearch2").Placeholder("search...").CssClass("searchtxt")
</div>
</div>

@Html.InitDeletePopupForGrid(grid2Id, "GridInlineEditDemo")

@(Html.Awe().Grid(grid2Id)
.Mod(o => o.Main(false))
.Url(Url.Action("GridGetItems", "GridInlineEditDemo"))
.InlEdit(new InlEditOpt {
SaveUrl = Url.Action("Save", "GridInlineEditDemo"),
RowClickEdit = true,
})
.Validation()
.Parent("txtSearch2", "search")
.Height(350)
.Resizable()
.Reorderable()
.Attr("data-syncg", "dinner")
.Columns(
new Column { Bind = "Id", Width = 75 }
.InlId()
.InlVldSummary(),

new Column { Bind = "Name" }
.InlString(),

new Column { Bind = "Date", Width = 160 }
.InlDate(),

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

new Column { Prop = "Meals", Header = "Meals", MinWidth = 250 }
.InlMultiselect(new MultiselectOpt { Name = "MealsIds", Url = Url.Action("GetMealsImg", "Data") }),

new Column { Bind = "BonusMeal.Name", Prop = "BonusMeal", Header = "Bonus Meal" }
.InlDropdownList(new DropdownListOpt { Name = "BonusMealId", Url = Url.Action("GetMealsImg", "Data") }),

new Column { Bind = "Organic", Width = 90, Prop = "DispOrganic" }
.Inl(Html.Awe().Toggle(new ToggleOpt { Name = "Organic" })),

Html.InlEditDelColumn(grid2Id)))



Comments