Grid custom render

Custom rendering achieved using mods that override grid api methods

Grid Cards View



Grid cards view achieved by overriding api methods, columns can be reordered, hidden/shown, and the changes will be reflected in the rendered card. The column headers width is ignored for calculating grid content width, so when you shrink the browser window the grid content won't get a horizontal scrollbar. On touch you can scroll the grid header horizontally by dragging from the left an right sides of the grid header.
Shared/Demos/GridCardsView.cshtml
@(Html.Awe().Grid("GridCardsView")
.CssClass("scrlh") // scrollbar for grid header when needed
.Reorderable()
.Mod(o => o.Main().CustomRender("cardsview"))
.Columns(
new Column { Bind = "Id", Width = 75, Groupable = false, Resizable = false },
new Column { Bind = "Person" }.Mod(o => o.Nohide()),
new Column { Bind = "Food.Name" },
new Column { Bind = "Location" },
new Column { Bind = "Date", Width = 120 }.Mod(o => o.Autohide()),
new Column { Bind = "Country.Name", Header = "Country" },
new Column { Bind = "Chef.FirstName,Chef.LastName", Prop = "ChefName", Header = "Chef" })
.Url(Url.Action("GetItems", "LunchGrid"))
.Resizable()
.Height(450))
<script>
function cardsview(o) {
var api = o.api;

// node content add wrap for padding
api.ncon = function(p) {
if (!p.lvl) return p.ren();
return '<div style="padding-left:' + p.lvl + 'em;" >' + p.ren() + '</div>';
};

// group header content
api.ghead = function(g) {
return api.ceb() + g.c;
};

// render item
api.itmf = function (opt) {
var columns = o.columns;

var content = '';
if (opt.con) {
content = opt.con;
} else {
for (var i = 0; i < columns.length; i++) {
var col = columns[i];

// is column hidden
if (api.ich(col)) continue;
content += '<div class="elabel">'+ (col.H ? col.H +': ' : '') + '</div>' + aweUtils.gcvw(api, col, opt) + '</br>';
}
}

if (opt.ceb) {
opt.clss += ' cardhead';
opt.style += 'margin-left:' + opt.ind + 'em;';
} else {
opt.clss += ' itcard';
}

var attr = opt.attr;
attr += ' class="' + opt.clss + '"';
opt.style && (attr += ' style="'+opt.style+'"');

return '<div ' + attr + '>' + content + '</div>';
};

// ignore columns width for grid content
o.syncon = 0;

// no alt rows
o.alt = 0;
}
</script>

Grid Custom Render with Inline Editing


Grid with custom rendering and inline editing mod applied. Edit on row click can also be used.
Shared/Demos/GridInlineCrudCustomRender.cshtml
@{
var gridId = "InlineCustomRender";
var initObj = new
{
Name = DemoUtils.RndName(),
Date = DateTime.Now.ToShortDateString(),
ChefId = DemoCache.Chefs.First().Id,
MealsIds = DemoCache.Meals.Take(2).Select(o => o.Id).ToArray()
};

}
<div class="bar">
<div style="float: right;">
@Html.Awe().TextBox("txtSearchInlCr").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)
.CssClass("scrlh inlEditCards")
.Attr("data-syncg", "dinner") // crud sync using signalr in site.js
.Url(Url.Action("GridGetItems", "GridInlineEditDemo"))
.InlEdit(new InlEditOpt { SaveUrl = Url.Action("Save", "GridInlineEditDemo") })
.Parent("txtSearchInlCr", "search")
.Height(620)
.Mod(o => o.PageInfo().CustomRender("inlDinner"))
.Columns(
new Column { Bind = "Id", Width = 75, Hidden = true }
.InlId(),

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

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

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

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

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

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

new Column { Id = "edit", ClientFormat = GridUtils.InlineEditFormat() },
new Column { Id = "del", ClientFormat = Html.InlineDeleteFormatForGrid(gridId) }))
@*column.Id edit/del used in inlDinner func*@
<script>
function inlDinner(o) {
var api = o.api;

// node (group) content add wrap for padding
api.ncon = function (p) {
if (!p.lvl) return p.ren();
return '<div style="padding-left:' + p.lvl + 'em;" >' + p.ren() + '</div>';
};

// group header content
api.ghead = function (g) {
return api.ceb() + g.c;
};

// render item (row)
api.itmf = function (opt) {
var content = '';

// content already set (group header)
if (opt.con) {
content = opt.con;
} else {
var colByBind = function (bind) {
return aweUtils.columnByBind(o, bind);
};

var colById = function (id) {
return aweUtils.columnById(o, id);
};

// get column value
function val(col, cls) {
return aweUtils.gcvw(api, col, opt, cls);
}

function field(col, nolabel) {
var label = '';
if (col.H && !nolabel) {
label = '<div class="elabel">' + col.H + ':</div> ';
}
return '<div class="efield">' + label + '<div class="einput">' + val(col) + '</div></div>';
}

function hid(col) {
return '<div style="display:none;">' + val(col) + '</div>';
}

content += hid(colByBind('Id')) +
'<div class="earea">' +
field(colByBind('Name')) +
field(colByBind('Date')) +
field(colById('chef')) +
'</div><div class="earea">' +
field(colByBind('BonusMeal.Name')) +
field(colByBind('Organic')) +
'</div>' +
field(colById('meals')) +
'<div class="inlbtns">' +
val(colById('edit'), 'awe-il') +
val(colById('del'), 'awe-il') +
'</div>';
}

// has collapse button
if (opt.ceb) {
opt.clss += ' cardhead';
opt.style += 'margin-left:' + opt.ind + 'em;';
} else {
opt.clss += ' edcard';
}

var attr = opt.attr;
attr += ' class="' + opt.clss + '"';
opt.style && (attr += ' style="' + opt.style + '"');

return '<div ' + attr + '>' + content + '</div>';
};

// ignore columns width for grid content
o.syncon = 0;

// no alt rows
o.alt = 0;
}
</script>

Tree grid with custom rendering



Using custom render mod to override api methods and render the grid using divs with padding instead of the default table.
Shared/Demos/TreeGridCustomRender.cshtml
@(Html.Awe().Grid("TreeGridCr")
.Url(Url.Action("SimpleTree", "TreeGrid"))
.Mod(o => o.CustomRender("crtree"))
.Columns(
new Column { Bind = "Name" },
new Column { Bind = "Id", Width = 100 }
)
.Groupable(false)
.PageSize(3)
.Height(400))
<script>
function crtree(o) {
var api = o.api;

// node content wrap
api.ncon = function (p) {
// don't wrap at level 0 and nodetype = items
if (!p.lvl || p.gv.nt == 2) return p.ren();
return '<div style="padding-left:' + p.lvl + 'em;" >' + p.ren() + '</div>';
};

// node
api.nodef = function (p) {
var attr = p.h ? 'style="display:none;"' : '';
if (p.lvl == 1) {
var res = '<div class="tgroot" ' + attr + '>' + p.ren() + '</div>';
return res;
}

return p.ren();
};

// group header content
api.ghead = function (g, lvl) {
return api.ceb() + g.c;
};

// render row
api.itmf = function (opt) {
function val(col) {
return aweUtils.gcv(api, col, opt);
}

var content = '';
if (opt.con) {
content = opt.con;
} else {
if (opt.ceb) content += api.ceb();
content += val(aweUtils.columnByBind(o, 'Name'));
}

if (opt.ceb) {
opt.clss += ' tgitem awe-ceb';
} else {
opt.clss += ' tgitem';
}

var attr = opt.attr;
attr += ' class="' + opt.clss + '"';
opt.style && (attr += ' style="' + opt.style + '"');

return '<div ' + attr + '>' + content + '</div>';
};
}
</script>

Tree grid nested cards



Rendering the grid nodes as cards and placing the child nodes inside the parent card. The grid is also using lazy loading.
GridCustomRender/Index.cshtml
<h2> Tree grid nested cards </h2>
@(Html.Awe().Grid("LazyTreeGridCr")
.Url(Url.Action("LazyTree", "TreeGrid"))
.Mod(o => o.CustomRender("cardstree"))
.Columns(
new Column {Bind = "Name"},
new Column {Bind = "Id", Width = 100})
.PageSize(3)
.Height(500))
<script>
function cardstree(o) {
var api = o.api;

// node
api.nodef = function(p) {
// don't wrap nodetype = items
if (p.gv.nt == 2) return p.ren();
var attr = p.h ? 'style="display:none;"' : ''; // collapsed
var res = '<div class="gwrap" ' + attr + '>' + p.ren() + '</div>';
return res;
};

// group header content
api.ghead = function(g) {
return api.ceb() + g.c;
};

// render row
api.itmf = function(opt) {
function val(col) {
return aweUtils.gcv(api, col, opt);
}

var content = '';
if (opt.con) {
content = opt.con;
} else {
if (opt.ceb) content += api.ceb();
content += val(aweUtils.columnByBind(o, 'Name'));
}

if (opt.ceb) {
opt.clss += ' cardhead awe-ceb';
} else {
opt.clss += ' itcard';
}

var attr = opt.attr;
attr += ' class="' + opt.clss + '"';
opt.style && (attr += ' style="' + opt.style + '"');

return '<div ' + attr + '>' + content + '</div>';
};

// ignore columns width for content
o.syncon = 0;
}
</script>



Comments