Grid inline editing always in edit mode
Grid inline editing with Always edit mode and batch save.
StopLoad is set, so the grid won't load (change page, sort) if there are unsaved changes, and will scroll to first row with changes.
We could also handle the change event on the grid, and call grid api batchSave to save instantly on each change.
StopLoad is set, so the grid won't load (change page, sort) if there are unsaved changes, and will scroll to first row with changes.
We could also handle the change event on the grid, and call grid api batchSave to save instantly on each change.
Shared/Demos/GridAlwaysEdit.cshtml
@{
var gridId = "GridAlwaysEdit";
}
<div class="bar">
<button type="button" onclick="$('#@gridId').data('api').inlineCreate()" class="awe-btn">Create</button>
<button type="button" onclick="$('#@gridId').data('api').batchSave()" class="awe-btn alwEdStBtn">Save All</button>
<button type="button" onclick="$('#@gridId').data('api').inlineCancelAll()" class="awe-btn alwEdStBtn">Cancel All (Undo changes)</button>
</div>
@Html.InitDeletePopupForGrid(gridId, "GridInlineEditDemo")
@(Html.Awe().Grid(gridId)
.Mod(o => o.Main(false))
.Url(Url.Action("GridGetData", "GridInlineBatchEditing"))
.InlEdit(new InlEditOpt
{
SaveUrl = Url.Action("BatchSave", "GridInlineBatchEditing"),
Batch = true,
AlwaysEdit = true,
StopLoad = true
})
.CssClass("noalt") // no alt color rows
.Height(390)
.Resizable()
.Reorderable()
.Attr("data-syncg", "dinner")
.Columns(
new Column { Bind = "Id", Width = 75 }
.InlId(),
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, Grow = 2 }
.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")
}
.ImgItem()),
new Column { Bind = "Organic", Width = 90, Prop = "DispOrganic" }
.Inl(Html.Awe().Toggle(new ToggleOpt { Name = "Organic" })),
Html.InlCancelColumn(),
Html.InlDeleteAlwaysColumn(gridId)
))
@*name of each inline helper/editor is matching the names of DinnerInput properties, and the names of row model properties set in MapToGridModel*@
@* certain helper data urls are configured to be cached globally (in site.js),
that's why when the grid loads all rows in edit mode you may not notice 10 xhr requests for Url.Action("GetChefs", "Data"), Url.Action("GetMealsImg", "Data"), etc. *@
<script>
// disable/enable save and cancel buttons when the grid has changed or new rows
$(function () {
var grid = $('#@gridId');
updateBtnState();
grid.on('change awerender awerowch', updateBtnState);
});
function updateBtnState() {
var grid = $('#@gridId');
$('.alwEdStBtn').prop('disabled', !grid.find('.o-hasch, .o-glnew').length);
}
</script>
@*optional grid client instant validation (for MVC5 must be placed in a cshtml with @model DinnerInput)*@
@(Html.BindOVldForId<DinnerInput>(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();
}
}
Comments