Grid Filtering

Filter grid using parent controls

The grid can be filtered by adding parent controls to it, when a parent control triggers the change event, the grid (child) will reload and the parent values will be sent as parameters to the data function (or url in this case).

Grid filtering using a popup to enter the search criteria

Using a popupForm and the grid api to filter the grid. The search criteria is built inside the popup, and when the Ok button is clicked, the post function executes, this is where the grid api.load function is called.
Note: we used aweui to initialize the popupForm, and a formBuilder util class to build its content (just like in the aweui grid filtering demo); an alternative would be to use the PopupForm helper and instead of the formBuilder we could set the Url to point to an action that returns a partial view with the search criteria form.
<div class="bar">
<button type="button" class="awe-btn" onclick="'filterGrid', {}, event)">Filter</button>
<button type="button" class="awe-btn" onclick="clearFilter()">Clear Filter</button>
.Mod(o => o.Main())
new Column { Bind = "Id", Width = 75, Groupable = false, Resizable = false },
new Column { Bind = "Person" },
new Column { Bind = "Food.Name", ClientFormatFunc = "site.imgFood", MinWidth = 200 },
new Column { Bind = "Country.Name", Header = "Country" },
new Column { Bind = "Date", Width = 120 }.Mod(o => o.Autohide()),
new Column { Bind = "Location" }.Mod(o => o.Autohide()),
new Column { Bind = "Chef.FirstName,Chef.LastName", Prop = "ChefName", Header = "Chef" })
.Url(Url.Action("LunchGridFilter", "Data"))

<script src="@Url.Content("~/js/infra/formBuilder.js")"></script>
var filterModel = {};

function clearFilter() {
filterModel = {};

function filterGrid() {
var api = $('#GridPopupFilter').data('api');
params: filterModel

$(function () {
id: 'filterGrid',
title: 'Filter grid',
height: 0,
dropdown: true,
loadOnce: true,
setCont: function (sp, o) {
var b = formBuilder({ model: filterModel, sp: sp });
b.add({ prop: 'person', func: aweui.txt });
b.add({ prop: 'food', func: aweui.txt });
prop: 'country',
func: aweui.radioList,
opt: {
url: '@Url.Action("GetCountries", "Data")',
odropdown: true
b.add({ prop: 'location', func: aweui.txt });
b.add({ prop: 'date', func: aweui.datepicker });
prop: 'chef',
func: aweui.lookup,
opt: {
getUrl: '@Url.Action("GetItem","ChefLookup")',
searchUrl: '@Url.Action("Search", "ChefLookup")'
postFunc: function (sp) {
var vm = utils.getParams(sp);
filterModel = vm;
return {};
public IActionResult LunchGridFilter(
GridParams g,
int? country,
int? chef,
DateTime? date,
string person = "",
string food = "",
string location = "")
var list = mcx.Lunches
.Include(o => o.Food)
.Include(o => o.Country)
.Include(o => o.Chef)
.Where(o => o.Food.Name.Contains(food)
&& o.Person.Contains(person)
&& o.Location.Contains(location))

if (country.HasValue) list = list.Where(o => o.Country.Id == country);
if (chef.HasValue) list = list.Where(o => o.Chef.Id == chef);
if (date.HasValue) list = list.Where(o => o.Date == date);

return Json(new GridModelBuilder<Lunch>(list, g)
KeyProp = o => o.Id,// needed for Entity Framework | nesting | tree | api
Map = o => new
FoodName = o.Food.Name,
FoodPic = o.Food.Pic,
Date = o.Date.ToShortDateString(),
CountryName = o.Country.Name,
ChefName = o.Chef.FullName

Filter by all columns

  you can search multiple columns at the same time (try 'pizza tavern')

Filtering by multiple columns at once from one textbox, you can type multiple keywords separated by space and the grid will get filtered.
The grid data is loaded once from the server after it is stored in the 'lunches' variable. The function defined in DataFunc can either return the grid model or a promise which will return the grid model later, and in this case on the first load we return a promise ($.get).
<div class="bar">
@Html.Awe().TextBox("txtsearch").Placeholder("search ...").CssClass("searchtxt")
<span class="hint">&nbsp; you can search multiple columns at the same time (try 'pizza tavern')</span>

.Mod(o => o.Main())
.Parent("txtsearch", "search", false)
new Column { Bind = "Id", Width = 75, Groupable = false, Resizable = false },
new Column { Bind = "Person" },
new Column { Bind = "FoodName", Header = "Food" },
new Column { Bind = "Location" },
new Column { Bind = "Date", Width = 120 },
new Column { Bind = "CountryName", Header = "Country" },
new Column { Bind = "ChefName", Header = "Chef" }))
function loadGridClientData(sgp) {
// cache storage used by this demo (cstorg.js), it will load data on first call
return $.when(cstorg.get('@Url.Action("GetLunches", "Data")')).then(function(lunches) {
return getGridClientData(sgp, lunches);

function getGridClientData(sgp, lunches) {
var where = awef.where, contains = awef.scont, loop = awef.loop;
var gp = utils.getGridParams(sgp);
var list = lunches;

if ( {
var words =" ");

list = where(lunches, function (o) {
var matches = 0;
loop(words, function (w) {
if (contains(o.FoodName, w) || contains(o.Person, w) || contains(o.Location, w) || contains(o.CountryName, w)
|| contains(o.DateStr, w)
|| contains(o.ChefName, w)) matches++;

return matches === words.length;

function map(o) { return { Id: o.Id, Person: o.Person, FoodName: o.FoodName, Location: o.Location,
Date: o.DateStr, CountryName: o.CountryName, ChefName: o.ChefName }; };

return utils.gridModelBuilder(
gp: gp,
items: list,
// replace default group header value for Date column
getHeaderVal:{ Date: function(o){ return o.DateStr; } }

$(function() {
$('#txtsearch').keyup(function() {

Grid outside filter row and custom render

Reusing the same data source (url) as for the Grid with filter row (server side data), except in this demo we're using the controls outside of the grid to filter the demo.
Just like in the filter row demos the filter controls get their data from the grid model.
Additionally there is filter persistence, so after page refresh the grid will have the same filters applied.
And there's a custom item render mod applied so you can switch between cards view and rows.