Grid using Array datasource

In this demo you can see how an array data source can be used to provide data for the awesome grid control.


Grid using a two-dimensional Array[][] as datasource.
When grid configuration and columns are not known until we get the data for the 1st time we could use the approach shown here.
In the controller's action that returns data we can set the grid model UpdateCfg property with the new configuration for the grid, this will make the grid update its configuration, and columns.
We're generating the configuration by rendering a partial view that contains only a grid helper with .UpdateCfg(true) set.
Shared/Demos/GridArrayDataSource.cshtml
@(Html.Awe().Grid("GridArrayData")
.Url(Url.Action("GridGetData", "GridArrayDataSource"))
.Mod(o => o.Main())
.Height(450))

<script>
function getVal(i) {
return function (model) {
if (model.Values) { // could be .values depending on json serialization rules
return model.Values[i];
}
};
}
</script>
Demos/Grid/GridArrayDataSourceController.cs
public IActionResult GridGetData(GridParams g, FilterPrm fprm, bool? init)
{
var initData = getLunchesTwoDimensArrayData(); // two-dimensional array data, 1st row has the header
// we can sort and page the data before passing it to the GridModelBuilder
// using gmb.GetPage, gmb.OrderBy (example CustomQueryingController.GetEfAsyncItems)
// or manually making use of g.Page, g.PageSize, g.SortNames, g.SortDirections

var header = initData[0];

var query = initData.Skip(1); // skip header

// Note: in the view (GridCfg.cshml) Column.Bind is set to the data's column index value
// below we usually use Convert.ToInt32(bind) to get the column index

#region filter data
if (fprm != null && fprm.Forder != null)
{
foreach (var bind in fprm.Forder)
{
var index = Convert.ToInt32(bind);
var fltVal = Request.Form[bind];
var name = header[index].ToString();

if (name == "Price")
{
var intval = Convert.ToInt32(fltVal);
query = query.Where(row => object.Equals(row[index], intval));
}
else
{
query = query.Where(row => row[index].ToString().ToLower().Contains(fltVal.ToString().ToLower()));
}
}
}
#endregion

// transform data to GridArrayRow[]
var data = query.ToArray();
var items = new List<GridArrayRow>();
for (var i = 0; i < data.Length; i++)
{
items.Add(new GridArrayRow { Id = data[i][0], Values = data[i] });
}

// build grid model
var gmb = new GridModelBuilder<GridArrayRow>(items.AsQueryable(), g);

// define get col value by index, used for grouping
gmb.GetColValFunc = (bind, row) =>
{
var index = Convert.ToInt32(bind);
return new[] { row.Values[index] };
};

// define orderby for array, used by sorting, grouping
gmb.OrderByFunc = ArrayRowOrderBy;

var model = gmb.BuildModel();

// update grid cfg only on first request, GridCfg helper has .Parameter("init", true)
// the helper in Index.cshtml doesn't have init param, so it will enter here 1st time
if (init != true)
{
model.UpdateCfg = this.RenderPartialView("GridCfg", header);
}

return Json(model.ToDto());
}
GridArrayDataSource/GridCfg.cshtml
@model string[]
@{
var header = Model;
var columns = new List<Column>();
columns.Add(new Column { Header = "Id", Prop = "Id", Width = 100 });

for (var i = 1; i < header.Length; i++)
{
var name = header[i];
var col = new Column { Bind = i.ToString(), Header = name, ClientFormatFunc = "getVal(" + i + ")" };

// identifying column by name example,
// instead of @model string[] we could use a more complex type to better define individual columns
if (name == "Price")
{
col.FltNumeric(new NumericInputOpt { Placeholder = name });
}
else
{
col.FltString(new TextBoxOpt { Placeholder = name });
}

columns.Add(col);
}
}
@(Html.Awe().Grid("GridArrayData")
.Url(Url.Action("GridGetData"))
.Mod(o => o.FilterRow().Main())
.Height(450)
.Parameter("init", true)
.Columns(columns.ToArray())
.UpdateCfg(true))
@*
partial view used to set grid cfg to gridModel.UpdateCfg,
the view must contain only the grid helper with .UpdateCfg(true)
*@
ViewModels/GridArrayRow.cs
namespace AweCoreDemo.ViewModels
{
public class GridArrayRow
{
public object Id { get; set; }

public object[] Values { get; set; }
}
}

Change Grid from dropdown

Data type:

Change grid configuration each time we change the value of the dataTypeDropdown.
In the GridGetData action we check if the value of dataTypeDropdown (sent using parent binding) is different from the value of cfgDataType (the parameter we set in SelGridCfg.cshtml), when they differ we set the new configuration to UpdateCfg property.
GridArrayDataSource/Index.cshtml
<script>
function getDataTypeItems() {
return [
{k: "", c: "not selected"},
{k: "Meals", c: "Meals"},
{k: "Lunches", c: "Lunches"},
{k: "Categories", c: "Categories"}
];
}
</script>
<div class="bar">
Data type:
@(Html.Awe().DropdownList(new DropdownListOpt {
Name = "dataTypeDropdown",
DataFunc = "getDataTypeItems"
}))
</div>

@(Html.Awe().Grid("SelGridArray")
.Url(Url.Action("SelGridGetData", "GridArrayDataSource"))
.Height(450)
.Load(false)
.Parent("dataTypeDropdown", "dataType"))

<script>
function getVal(i) {
return function (model) {
if (model.Values) { // could be .values depending on json serialization rules
return model.Values[i];
}
};
}
</script>
Demos/Grid/GridArrayDataSourceController.cs

public IActionResult SelGridGetData(GridParams g, FilterPrm fprm, string dataType, string cfgDataType)
{
var initData = new object[][] { new object[] { } };
if (dataType == "Meals") initData = getMealsTwoDimensArrayData();
if (dataType == "Lunches") initData = getLunchesTwoDimensArrayData();
if (dataType == "Categories") initData = getCategoriesTwoDimensArrayData();

var headers = initData[0].Select(o => o.ToString()).ToArray();

var query = initData.Skip(1); // skip header

#region filter data
if (dataType != cfgDataType)
{
fprm = null; // ignore previous filters when changing data type
}

if (fprm != null && fprm.Forder != null)
{
foreach (var bind in fprm.Forder)
{
var index = Convert.ToInt32(bind);
var fltVal = Request.Form[bind];
var name = headers[index].ToString();

if (name == "Price")
{
var intval = Convert.ToInt32(fltVal);
query = query.Where(row => object.Equals(row[index], intval));
}
else
{
query = query.Where(row => row[index].ToString().ToLower().Contains(fltVal.ToString().ToLower()));
}
}
}
#endregion

// transform data to GridArrayRow[]
var data = query.ToArray();
var items = new List<GridArrayRow>();
for (var i = 0; i < data.Length; i++)
{
items.Add(new GridArrayRow { Id = data[i][0], Values = data[i] });
}

// build grid model
var gmb = new GridModelBuilder<GridArrayRow>(items.AsQueryable(), g);

// define get col value by index, used for grouping
gmb.GetColValFunc = (bind, row) =>
{
var index = Convert.ToInt32(bind);
return new[] { row.Values[index] };
};

// define orderby for array, used by sorting, grouping
gmb.OrderByFunc = ArrayRowOrderBy;

var model = gmb.BuildModel();

// when dataType dropdown value changed update the grid
if (cfgDataType != dataType)
{
model.UpdateCfg = this.RenderPartialView("SelGridCfg", new SelGridCfg { Headers = headers, DataType = dataType });
}

return Json(model.ToDto());
}
GridArrayDataSource/SelGridCfg.cshtml
@using AweCoreDemo.Controllers.Demos.Grid;
@model SelGridCfg
@{
var header = Model.Headers;
var columns = new List<Column>();

if (Model.DataType != null)
{
columns.Add(new Column { Header = "Id", Prop = "Id", Width = 100 });
}

for (var i = 1; i < header.Length; i++)
{
var name = header[i];
var col = new Column { Bind = i.ToString(), Header = name, ClientFormatFunc = "getVal(" + i + ")" };

// identifying column by name example,
// instead of @model string[] we could use a more complex type to better define individual columns
if (name == "Price")
{
col.FltNumeric(new NumericInputOpt { Placeholder = name });
}
else
{
col.FltString(new TextBoxOpt { Placeholder = name });
}

if (name == "Description")
{
col.Grow = 5;
}

columns.Add(col);
}
}
@(Html.Awe().Grid("SelGridArray")
.Url(Url.Action("SelGridGetData"))
.Mod(o => o.FilterRow().Main())
.Height(450)
.Load(Model.DataType != null)
.Parameter("cfgDataType", Model.DataType)
.Parent("dataTypeDropdown", "dataType")
.Columns(columns.ToArray())
.UpdateCfg(true))
ViewModels/GridArrayRow.cs
namespace AweCoreDemo.ViewModels
{
public class GridArrayRow
{
public object Id { get; set; }

public object[] Values { get; set; }
}
}



Comments