Hello Caleb!
Based on the sample
test case you provided on your previous thread, and also the
GridFilters Remote sample, we've extended it to this:
<%@ Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
// Just a variable to "emulate" the many or few data, being true, should use server-side filtering.
public static bool bigdata = true;
// Define model classes to make code more readable
public class MapItem
{
public int IDVal { get; set; }
public string DisplayVal { get; set; }
}
public class DataItem
{
public string businessVal { get; set; }
public int FK_ID { get; set; }
}
// The same data should be accessed from different places (e.g. data available on database)
public static List<MapItem> MapData = new List<MapItem>
{
new MapItem {IDVal = 0, DisplayVal = "Some"},
new MapItem {IDVal = 1, DisplayVal = "Something"},
new MapItem {IDVal = 2, DisplayVal = "Somehow"},
new MapItem {IDVal = 3, DisplayVal = "Someway"},
new MapItem {IDVal = 4, DisplayVal = "Someone"}
};
public static List<DataItem> Data = new List<DataItem>
{
new DataItem {businessVal = "Record A: Some", FK_ID = 0},
new DataItem {businessVal = "Record B: Something", FK_ID = 1},
new DataItem {businessVal = "Record C: Some", FK_ID = 0},
new DataItem {businessVal = "Record D: Something", FK_ID = 1},
new DataItem {businessVal = "Record E: Somehow", FK_ID = 2},
new DataItem {businessVal = "Record F: Some", FK_ID = 0}
};
protected void Page_Load(object sender, EventArgs e)
{
MapStore.DataSource = MapData;
MapStore.DataBind();
if (bigdata)
{
GridStore.RemoteFilter = true;
MaskedColumn.Filter.Add(new StringFilter());
}
else
{
// make the grid use local filtering
// GridStore.RemoteFilter = false; // this is the setting by default, no need to force
MaskedColumn.Filter.Add(new StringFilter()
{
CustomConfig = { new ConfigItem() { Name = "filterFn", Value = "filterFn_DisplayVal", Mode = ParameterMode.Raw } }
});
}
}
// Get the entry given its ID.
private string getMapDataByID(int id)
{
return MapData.First(entry => entry.IDVal == id).DisplayVal;
}
// Extracted from https://examples4.ext.net/#/GridPanel/Plugins/GridFilters_Remote/
protected void GridStore_RefreshData(object sender, StoreReadDataEventArgs e)
{
var gridData = new List<DataItem>(); // benefit from the List class facilities
// create a copy of the data (or changes in the list will affect the
// static variable)
gridData.AddRange(Data);
// The filter will be empty on first load (and no following queries
// will be made if sorting is local).
string s = e.Parameters["filter"];
if (!string.IsNullOrEmpty(s))
{
FilterConditions fc = new FilterConditions(s);
foreach (FilterCondition condition in fc.Conditions)
{
Comparison comparison = condition.Comparison;
string field = condition.Field;
FilterType type = condition.Type;
object value;
switch (condition.Type)
{
case FilterType.Boolean:
value = condition.Value<bool>();
break;
case FilterType.Date:
value = condition.Value<DateTime>();
break;
case FilterType.List:
value = condition.List;
break;
case FilterType.Number:
if (gridData.Count > 0 && gridData[0].GetType().GetProperty(field).PropertyType == typeof(int))
{
value = condition.Value<int>();
}
else
{
value = condition.Value<double>();
}
break;
case FilterType.String:
value = condition.Value<string>();
break;
default:
throw new ArgumentOutOfRangeException();
}
gridData.RemoveAll(
item =>
{
object oValue = item.GetType().GetProperty(field).GetValue(item, null);
// If the field filtered is the one we want the special
// behavior then just replace the value to check
// against to its string mapped value
if (field == "FK_ID")
{
// No reflection needed, we know we want FK_ID in this case.
oValue = getMapDataByID(item.FK_ID);
}
IComparable cItem = oValue as IComparable;
switch (comparison)
{
case Comparison.Eq:
if (type == FilterType.List)
{
return !(value as List<string>).Contains(oValue.ToString());
}
return !cItem.Equals(value);
case Comparison.Like:
switch (type)
{
case FilterType.List:
return !(value as List<string>).Any(val => oValue.ToString().Contains(val));
case FilterType.String:
return !oValue.ToString().Contains(value.ToString());
default:
return !cItem.Equals(value);
}
case Comparison.In:
switch (type)
{
case FilterType.List:
return !(value as List<string>).Contains(oValue.ToString());
case FilterType.String:
return !oValue.ToString().StartsWith(value.ToString());
default:
return !cItem.Equals(value);
}
case Comparison.Gt:
return cItem.CompareTo(value) < 1;
case Comparison.Lt:
return cItem.CompareTo(value) > -1;
default:
throw new ArgumentOutOfRangeException();
}
}
);
}
}
GridStore.DataSource = gridData;
GridStore.DataBind();
}
protected void Toggle_BigData(object sender, DirectEventArgs e)
{
bigdata = !bigdata;
X.Reload();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>61872 - Custom header dropdown filter (user provided)</title>
<script type="text/javascript">
var lookupDisplayVal = function (IDValue) {
var mappingEntry = App.MapStore.getById(IDValue);
if (Ext.isEmpty(mappingEntry)) {
return IDValue;
}
return mappingEntry.data.DisplayVal;
};
var filterFn_DisplayVal = function (gridrow, filterVal) {
//in a non-hardcoded situation with undetermined number of columns, is there a good way for this filterFn handler to identify which gridview column links to the filterVal?
var lookupVal = lookupDisplayVal(gridrow.data.FK_ID);
if (Ext.isEmpty(lookupVal)) {
return false;
}
return (lookupVal.toLowerCase().indexOf(filterVal.toLowerCase()) > -1);
};
</script>
</head>
<body>
<form runat="server">
<ext:ResourceManager runat="server" />
<ext:Store ID="MapStore" runat="server">
<Model>
<ext:Model runat="server" IDProperty="IDVal">
<Fields>
<ext:ModelField Name="IDVal" Type="Int" />
<ext:ModelField Name="DisplayVal" Type="String" />
</Fields>
</ext:Model>
</Model>
</ext:Store>
<ext:GridPanel Title="Grid Panel" ID="GridPanel1" runat="server" Width="650" Height="325">
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:Button runat="server" Text="Toggle big data" OnDirectClick="Toggle_BigData" />
<ext:Label runat="server">
<Content>
Big data approach (remote filtering) is: <b><%: bigdata %></b>
</Content>
</ext:Label>
</Items>
</ext:Toolbar>
</TopBar>
<Store>
<ext:Store ID="GridStore" runat="server" OnReadData="GridStore_RefreshData">
<%-- This makes the server-side requests to load data (including first load).
Makes server side request for filters if RemoteFilter is true. --%>
<Proxy>
<ext:PageProxy />
</Proxy>
<Model>
<ext:Model runat="server">
<Fields>
<ext:ModelField Name="businessVal" Type="String" />
<ext:ModelField Name="FK_ID" Type="Int" />
</Fields>
</ext:Model>
</Model>
</ext:Store>
</Store>
<ColumnModel runat="server">
<Columns>
<ext:Column runat="server" Text="ExampleVals" DataIndex="businessVal" Flex="1">
<Filter>
<ext:StringFilter />
</Filter>
</ext:Column>
<ext:Column ID="MaskedColumn" runat="server" Text="Masked FK Editor" DataIndex="FK_ID" Flex="2">
<Renderer Fn="lookupDisplayVal" />
<Editor>
<ext:ComboBox
runat="server"
QueryMode="Local"
Editable="true"
StoreID="MapStore"
DisplayField="DisplayVal"
ValueField="IDVal"
/>
</Editor>
</ext:Column>
</Columns>
</ColumnModel>
<Plugins>
<ext:CellEditing runat="server" />
<ext:GridFilters runat="server" />
</Plugins>
</ext:GridPanel>
</form>
</body>
</html>
Some considerations:
- I don't see much sense on switching the grid from local to remote without a full page reload (as the data in the database will be brought in during the page load) -- so the button to switch modes (to emulate either a big or a small database size) also reloads the page. Changes a static variable which is reset each time the server thread (IIS/IISExpress) is started/restarted.
- If you want to switch to "local filtering" once the filter reduces greatly the amount of entries, what if the user clears or chooses a filter which matches more entries? Any filter pattern in potential can bring all data from the server
- The server-side filtering logic should be tailored for your data, it is not a generic code that should work for all cases and is provided just to illustrate the functionality and some possibilities of extension (preserved from the
original example)
- To "see" the server queries, open browser's developer tools and go to the network monitor tab. Clear the requests and change the filter to see the requests being made. This won't happen when the "bigdata" variable is toggled to false with the
Toggle big data button.
Well, I hope this helps!