Ag-Grid QuickFilter changing programmatically searched columns - ag-grid

I need a quick search filter, where user can select what columns are searched. I didn't succeed to implement this behavior.
I tried this:
this.columns.forEach(column=>{
if (this.globalSearchSelectedColumns.indexOf(column.field)>-1) column.getQuickFilterText = (params)=> params.value.name;
else column.getQuickFilterText = ()=> '';
});
this.grid.api.setColumnDefs(this.columns);
this.grid.api.onFilterChanged();
this.grid.api.resetQuickFilter();
where this.columns is columns defs, this.grid is gridOptions, this.globalSearchSelectedColumns is the selected columns to search for, by column.field.

In order to selectively apply quickFilter form ag-Grid you should rewrite the property getQuickFilterText of the columnDef, by setting it to a function which returns an empty string like so:
First of all, you need to retrieve the column by a key through the gridColumnApi
Then you need to access its colDef
Lastly, all you left to do is to rewrite getQuickFilterText property
Assume, that in your class component you have a method disableFilterCol it can look something like this:
disableFilterCol = () => {
var col = this.gridColumnApi.getColumn("athlete");
var colDef = col.getColDef();
colDef.getQuickFilterText = () => "";
console.log("disable Athlete");
};
Once it called, quickFilter will be applied to your data grid excluding athlete column.
I created live demo for you on ReactJS.
You can improve the way you can select multiple columns that you want to rely on doing filtering.
I suppose that in your case you can try to add set getQuickFilterText = () => "" for either definition of colDef from the very beginning and let the user enabling particular columns, you can set getQuickFilterText property for them to undefined to provide sorting among them.

According to nakhodkiin solution I change my code like this:
this.grid.columnApi.getAllColumns().forEach(column=>{
let def = column.getColDef();
if (this.globalSearchSelectedColumns.indexOf(def.field)>-1) def.getQuickFilterText = undefined;
else def.getQuickFilterText = ()=> '';
});
this.grid.api.onFilterChanged();
And it's working;

I think the problem here lies in setting updated column defs.
Can you try this -
let newColDef= [];
this.columns.forEach(column=>{
if (this.globalSearchSelectedColumns.indexOf(column.field)>-1)
column.getQuickFilterText = (params)=> params.value.name;
else column.getQuickFilterText = ()=> '';
newColDef.push(column);
});
this.grid.api.setColumnDefs(newColDef);
this.grid.api.onFilterChanged();
this.grid.api.resetQuickFilter();
this.grid.api.refreshHeader();
Ag-grid updated its approach of detecting column changes since v19.1
More details here
As per doc -->
When new columns are set, the grid will compare with current columns and work out which > columns are old (to be removed), new (new
columns created) or kept (columns that remain will keep their state
including position, filter and sort).
Comparison of column definitions is done on 1) object reference comparison and 2)
column ID eg colDef.colId. If either the object
reference matches, or the column ID matches, then the grid treats the
columns as the same column.
Ag-grid team is also actively working on fixing this issue for v20.1. You can track it on github

Related

Added row moves to last position once filter is removed

In NatTable I am adding a row in filtered table. After removing the filter, the newly added row moves to last position in the table.
But I want to it to stay in the same position, that is next to the row which I added when the table is filtered.
I am currently using the RowInsertCommand. I don't want to add row via model or list which used to populated the table. I want to achieve only via NatTable commands. Is it possible?
It is always hard to follow the explanations and the issue without example code. But I assume you simply copied code from the NatTable examples, so I will explain your issue based on that.
First, the RowInsertCommand has several constructors. If you are using a constructor without a rowIndex or rowPositionparameter, the new object will ALWAYS be added at the end of the list.
When using the filter functionality in NatTable with GlazedLists, the list that is wrapped in the body DataLayer is the FilterList. If you are operating on the FilterList for calculating the rowIndex where the new object should be added and have the FilterList as base list in the RowInsertCommandHandler, the place where the new object is added is transformed between the FilterList and the base EventList, which might not be the desired result.
To solve this you need to create the RowInsertCommandHandler by using the base EventList.
EventList<T> eventList = GlazedLists.eventList(values);
TransformedList<T, T> rowObjectsGlazedList = GlazedLists.threadSafeList(eventList);
SortedList<T> sortedList = new SortedList<>(rowObjectsGlazedList, null);
this.filterList = new FilterList<>(sortedList);
this.baseList = eventList;
bodyDataLayer.registerCommandHandler(new RowInsertCommandHandler<>(this.baseList));
The action that performs the add operation then of course needs to calculate the index based on the base EventList. The following code is part of the SelectionAdapter of an IMenuItemProvider:
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
int rowIndex = natTable.getRowIndexByPosition(rowPosition);
Object relative = bodyLayerStack.filterList.get(rowIndex);
int baseIndex = bodyLayerStack.baseList.indexOf(relative);
Object newObject = new ...;
natTable.doCommand(new RowInsertCommand<>(baseIndex + 1, newObject));

ag-grid setModel equivalent of selectValue

Using ag-grid 23.2.1, it looks like our current approach to filtering is on it's way out and listed as deprecated. Reading over the setModel documentation, I don't readily see a way to replace some of our selectValue, selectNothing, etc. usage.
Example 1: we clear the selection and then pick a couple of values on some condition else we select all
let filterInstance = this.gridOptions.api.getFilterInstance('make');
this.cacheFilterModel = this.gridOptions.api.getFilterModel();
if (condition) {
filterInstance.selectNothing();
filterInstance.selectValue('thing1');
filterInstance.selectValue('thing2');
}
else {
filterInstance.selectEverything();
}
filterInstance.applyModel();
this.gridOptions.api.onFilterChanged();
Example 2: we have some filter values in a column toggle-able via checkboxes, which call a method like the below. if one of the values is checked it gets added to the existing filter, if unchecked the value is removed. There could be values already filtered and I don't really see a way to contextually select/unselect values using setModel.
filterExample (make, add) {
let filterInstance = this.gridOptions.api.getFilterInstance('make');
if (add) {
filterInstance.selectValue(make);
}
else {
filterInstance.unselectValue(make);
}
filterInstance.applyModel();
this.gridOptions.api.onFilterChanged();
}
Are there setModel equivalents for these?
I had a similar issue with setColumnFilter where I had to pass a few values. You can use filterInstance.setModel to set these values by passing an array like so:
filterInstance.setModel({ values: ['value1', 'value2'] })
filterInstance.applyModel();
gridOptions.api.onFilterChanged()
here is a link to how to do it from the docs. I found this hard to find on google so providing it here.
https://www.ag-grid.com/javascript-grid-filter-set-api/

How to delete empty rows from Grid in my Form?

I use to fill my StringEdit a simple displayMethod.
This method selected to see some records from myTable and discard others , this method work well, but, in my Grid I see the empty records-rows(that would be the record discarded).
For to fill my StringEdit I used this dispaly method :
display myEXDTypeString nameFIeld()
{
MYTable mineTable;
myEXDTypeString name;
while select mineTable
where this.FieldtoUse== "Value"
name = this.NameFIeld;
return name;
}
There's a way to delete the empty rows?
In my Grid
I have a Lesf site state , I want to have the right situation:
Thanks all!
Enjoy
If you are just trying to get the Form to not display blank records then it could be as easy as setting a QueryBuildRange on the data source:
QueryBuildDataSource queryBuildDataSource;
QueryBuildRange queryBuildRange;
super();
queryBuildDataSource = this.query().dataSourceName(mineTable_ds.name());
queryBuildRange = queryBuildDataSource.addRange(fieldNum(MineTable, FieldToUse));
queryBuildRange.value('>0');
I solved my problem: the cause is the Form DataSource relation.
OuterJoin Split my Lines.
Thanks all, enjoy!

MATLAB - Adding a field to the begining of an existing struct

I have a 1x100000 struct in MATLAB. It occurs to me that I need to add a field to it, which is easy and fine.. however i can't seem to add the field to the beginning i.e. make the new field the first field.
my struct looks like this
DB(kk).StudyDate
DB(kk).StudyTime
DB(kk).PatientName
i wish to make it
DB(kk).PatientID <---- new field
DB(kk).StudyDate
DB(kk).StudyTime
DB(kk).PatientName
and not
DB(kk).StudyDate
DB(kk).StudyTime
DB(kk).PatientName
DB(kk).PatientID <---- new field
this is more for aesthetics and presentation purposes than anything else as it won't really affect how the struct is used whether the new field is at the beginning or the end.
The orderfields function exists for this purpose:
% Order based on permuting current field ordering
DB = struct('StudyDate','2015/04/27','StudyTime',now(),'PatientName','Baz Bar');
DB.PatientID = dec2hex(randi([1,2^32]));
DB = orderfields(DB,[4,1,2,3]);
% Does the same with explicit fieldnames
DB = struct('StudyDate','2015/04/27','StudyTime',now(),'PatientName','Baz Bar');
DB.PatientID = dec2hex(randi([1,2^32]));
DB = orderfields(DB,{'PatientID','StudyDate','StudyTime','PatientName'});
The only way (AFAIK) to do this is to make a brand new struct and copy all the fields into it in the order you would like them displayed.

ADO.NET Mapping From SQLDataReader to Domain Object?

I have a very simple mapping function called "BuildEntity" that does the usual boring "left/right" coding required to dump my reader data into my domain object. (shown below) My question is this - If I don't bring back every column in this mapping as is, I get the "System.IndexOutOfRangeException" exception and wanted to know if ado.net had anything to correct this so I don't need to bring back every column with each call into SQL ...
What I'm really looking for is something like "IsValidColumn" so I can keep this 1 mapping function throughout my DataAccess class with all the left/right mappings defined - and have it work even when a sproc doesn't return every column listed ...
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim product As Product
While reader.Read()
product = New Product()
product.ID = Convert.ToInt32(reader("ProductID"))
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
Also check out this extension method I wrote for use on data commands:
public static void Fill<T>(this IDbCommand cmd,
IList<T> list, Func<IDataReader, T> rowConverter)
{
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
list.Add(rowConverter(rdr));
}
}
}
You can use it like this:
cmd.Fill(products, r => r.GetProduct());
Where "products" is the IList<Product> you want to populate, and "GetProduct" contains the logic to create a Product instance from a data reader. It won't help with this specific problem of not having all the fields present, but if you're doing a lot of old-fashioned ADO.NET like this it can be quite handy.
Although connection.GetSchema("Tables") does return meta data about the tables in your database, it won't return everything in your sproc if you define any custom columns.
For example, if you throw in some random ad-hoc column like *SELECT ProductName,'Testing' As ProductTestName FROM dbo.Products" you won't see 'ProductTestName' as a column because it's not in the Schema of the Products table. To solve this, and ask for every column available in the returned data, leverage a method on the SqlDataReader object "GetSchemaTable()"
If I add this to the existing code sample you listed in your original question, you will notice just after the reader is declared I add a data table to capture the meta data from the reader itself. Next I loop through this meta data and add each column to another table that I use in the left-right code to check if each column exists.
Updated Source Code
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim table As DataTable = reader.GetSchemaTable()
Dim colNames As New DataTable()
For Each row As DataRow In table.Rows
colNames.Columns.Add(row.ItemArray(0))
Next
Dim product As Product While reader.Read()
product = New Product()
If Not colNames.Columns("ProductID") Is Nothing Then
product.ID = Convert.ToInt32(reader("ProductID"))
End If
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
This is a hack to be honest, as you should return every column to hydrate your object correctly. But I thought to include this reader method as it would actually grab all the columns, even if they are not defined in your table schema.
This approach to mapping your relational data into your domain model might cause some issues when you get into a lazy loading scenario.
Why not just have each sproc return complete column set, using null, -1, or acceptable values where you don't have the data. Avoids having to catch IndexOutOfRangeException or re-writing everything in LinqToSql.
Use the GetSchemaTable() method to retrieve the metadata of the DataReader. The DataTable that is returned can be used to check if a specific column is present or not.
Why don't you use LinqToSql - everything you need is done automatically. For the sake of being general you can use any other ORM tool for .NET
If you don't want to use an ORM you can also use reflection for things like this (though in this case because ProductID is not named the same on both sides, you couldn't do it in the simplistic fashion demonstrated here):
List Provider in C#
I would call reader.GetOrdinal for each field name before starting the while loop. Unfortunately GetOrdinal throws an IndexOutOfRangeException if the field doesn't exist, so it won't be very performant.
You could probably store the results in a Dictionary<string, int> and use its ContainsKey method to determine if the field was supplied.
I ended up writing my own, but this mapper is pretty good (and simple): https://code.google.com/p/dapper-dot-net/