Grid Filter row client data

The filter row generates a dropdown for each column that it receives data from the data source (DataFunc or Url), and we can also specify a custom editor for the filter column.
We also take into account the order in which the user has selected the filters, so the filter dropdowns/multiselect will also get filtered based on the previous selected filter.
The filtering code is under your control so for example on the meals column we query the data and select the rows that contain all the selected meals, but you could change it to select the ones that contain any of the selected meals.
Filter row model is saved to sessionStorage so after page refresh the filters will be persisted; this code is custom so you can modify it to save to localStorage or server.
Shared/Demos/GridFilterClientData.cshtml
@(Html.Awe().Grid("GridFrow")
.Height(390)
.Reorderable()
.Resizable()
.Parent("txtGridFrowSrc", "search", false)
.DataFunc("loadLunchesGrid")
.Mod(o => o.Main().ColumnsAutohide().FilterRow().Custom("persistFilter"))
.Columns(
new Column { Bind = "Id", Width = 100 }
.FltFormat("Search:"),

new Column { Bind = "Person" }
.FltString(new TextBoxOpt().FltInstant()),

new Column { Bind = "FoodName", ClientFormatFunc = "site.imgFood", MinWidth = 200, Header = "Food" }
.FltDropdownList(new DropdownListOpt { Name = "Food", ClearBtn = true }.FoodImgItem()),

new Column { Bind = "Price", Width = 180 }
.FltNumericOp(),

new Column { Bind = "Date", Prop = "DateStr", Width = 230 }
.FltDateOp(),

new Column { Bind = "CountryName", Header = "Country" }
.Flt(valProp: "Country", type: FilterType.Multichk, clearBtn: false)
.Flt(Html.Awe().DropdownList(new DropdownListOpt { Name = "CountryOp", CssClass = "o-op", DataFunc = "countryOpData" }))
.FltClearBtn(),

new Column { Prop = "MealsStr", MinWidth = 200, Header = "Meals", Grow = 1.7 }
.Flt(valProp: "Meals", type: FilterType.Multiselect),

new Column { Bind = "ChefName", Header = "Chef" }))
<script>
function countryOpData() {
return [{ k: '', c: 'include' },
{ k: 'exclude', c: 'exclude' }];
}

// load client data and return grid model
function loadLunchesGrid(sgp) {
// cache storage used by this demo (cstorg.js), it will load data on first call,
// for no cache you can replace cstorg.get with $.get
return $.when(cstorg.get('@Url.Action("GetLunches", "Data")')).then(function (lunches) {
return buildGridModel(sgp, lunches);
});
}

function buildGridModel(sgp, lunches) {
var where = awef.where, select = awef.select, contains = awef.scont, loop = awef.loop;
var jsonToDate = utils.toDate; // json date str to date
var distLstFunc = utils.distLstFunc;
var gp = utils.getGridParams(sgp, ['country', 'meals']); // country, meals are arrays
var data = lunches;

// data used to populate some of the filter row dropdowns
var frowData = {};

var gfb = gridFilterBuilder();

// filter rules, will be applied in order ( gp.forder ),
// because we want to get the data for the dropdowns in order of filter application
var filterRules = {
Person: function () {
if (gp.person) {
data = where(data, function (o) { return contains(o.Person, gp.person) });
}
},
Food: function () {
var items = utils.distItmsFunc('FoodName')(data);

frowData.Food = [{ k: '', c: 'any', url: 'pasta.png' }]
.concat(select(items, function (o) { return { k: o.FoodName, c: o.FoodName, url: FoodPic = o.FoodPic } }));

if (gp.food) {
data = where(data, function (o) { return o.FoodName === gp.food });
}
},
Price: function () {
if (!gp.price) return;

var cond = gfb.opFunc({
op: gp.priceOp,
paramVal: gp.price,
itmValFunc: function (itm) { return itm.Price; }
});

data = where(data, cond);
},
Date: function () {
if (!gp.date) return;

var pdate = awem.toDate(gp.date); // parse str to date with datepicker default dateformat

var cond = gfb.opFunc({
op: gp.dateOp,
paramVal: pdate.valueOf(),
itmValFunc: function (itm) { return jsonToDate(itm.Date).valueOf() }
});

data = where(data, cond);
},
Meals: function () {
if (gp.meals) {
data = where(data, function (o) {
// check that each of gp.meals is present in o.Meals

var mids = select(o.Meals, function (m) { return m.Id; });

var hasAll = true;
loop(gp.meals, function (mid) {
hasAll = hasAll && awef.vcont(mid, mids);
});

return hasAll;
});
}

// get data after querying this time, to filter the meals dropmenu as well
var distMeals = [];
var udict = {};
loop(data, function (o) {
loop(o.Meals, function (m) {
if (!udict[m.Id]) {
distMeals.push(m);
udict[m.Id] = 1;
}
});
});

frowData.Meals = select(distMeals, function (m) { return { k: m.Id, c: m.Name }; });
},
CountryName: function () {
frowData.CountryName = toKeyContent(distLstFunc('CountryName')(data), 'any');
if (gp.countryName) {
data = where(data, function (o) { return o.CountryName === gp.countryName });
}
},
Country: function () {
frowData.Country = toKeyContent(distLstFunc('CountryName')(data));

if (!gp.country) return

// include
var op = function (o) {
var res = false;
loop(gp.country,
function (c) {
if (c === o.CountryName) res = true;
});

return res;
}

if (gp.countryOp === 'exclude') {
op = function (o) {
var res = true;
loop(gp.country,
function (c) {
if (c === o.CountryName) res = false;
});

return res;
}
}

data = where(data, op);
},
ChefName: function () {
frowData.ChefName = toKeyContent(distLstFunc('ChefName')(data).sort(), 'any');
if (gp.chefName) {
data = where(data, function (o) { return o.ChefName === gp.chefName });
}
},
};

// apply rules in order
gfb.apply({
rules: filterRules,
gp: gp
});

function toKeyContent(arr, emptyn) {
var res = [];

if (emptyn) res.push({ k: '', c: emptyn });

awef.loop(arr, function (item) {
res.push({ k: item, c: item });
});

return res;
}

var model = utils.gridModelBuilder(
{
key: "Id",
gp: gp,
items: data,

// replace default group header value for Date column
getHeaderVal: { Date: function (o) { return o.DateStr; } },
tag: { frow: frowData }
});

return model;
}
</script>
<script src="~/js/aweutil/gridFilterBuilder.js"></script>
<script src="~/js/aweutil/persistFrow.js"></script>

Awesome/DataController.cs
public IActionResult GetLunches()
{
return Json(mcx.Lunches.Take(200).Select(o => new
{
o.Id,
o.Person,
FoodName = o.Food.Name,
FoodPic = o.Food.Pic,
o.Location,
o.Price,
CountryName = o.Country.Name,
ChefName = o.Chef.FullName,
o.Date,
o.Date.Year,
DateStr = o.Date.ToShortDateString(),
Meals = o.Meals.Select(m => new { m.Id, m.Name }),
MealsStr = string.Join(", ", o.Meals.Select(m => m.Name))
}));
}



Comments