SmartGWT ListGrid with DataSource, Filter on CellFormatter output - filter

I'm using a SmartGWT ListGrid with a DataSource. I'm successfully using a CellFormatter to display numeric file size data as mixed text / data (i.e. "10 GB" rather than 10737418240). I have filtering set up.
What I'd like to do is to let the user filter on the CellFormatter output, rather than on the underlying data. IOW, let the user type "GB" into the filter box, and get all the files with sizes in the GB range. The DataSource is cached locally, so I don't have issues about going back to the server to get data.
Edit: the reason why I'm using a CellFormatter is because it want sorting to be correct, IOW when sorting in increasing order I want 200 KB to come before 10 GB, not after (and in a text sort they're reversed). Sorting is more important to me than filtering, so if I have to have both sorting and filtering target the same representation of the data, I'll just give up on filtering working.
Any help would be greatly appreciated. Thank you,
Greg

You have two options to do this. First is to return already modified values from your datasource, so instead of 10737418240 it should return "10 GB" string value.
The second approach seems better for me - you should use SimpleType functionality. There is an example for you:
public class PopulationType extends SimpleType {
public PopulationType() {
super("population", FieldType.TEXT);
// format values in the grid
this.setSimpleTypeValueExtractor(new SimpleTypeValueExtractor() {
#Override
public Object getAtomicValue(Object value) {
if (value instanceof Integer && ((Integer) value) > 1000000) {
return ((Integer) value) / 1000000 + " Mln";
}
return "" + value;
}
});
}
}
public void onModuleLoad() {
final ListGrid countryGrid = new ListGrid();
countryGrid.setWidth100();
countryGrid.setHeight100();
countryGrid.setAutoFetchData(true);
countryGrid.setShowFilterEditor(true);
countryGrid.setShowAllRecords(true);
WorldXmlDS ds = WorldXmlDS.getInstance();
ds.getField("population").setType(new PopulationType());
countryGrid.setDataSource(ds);
countryGrid.draw();
}
You set your SimpleType instance to a field you want to format and set SimpleTypeValueExtractor to override getAtomicValue which is used for showing,filtering,sorting.
There are other methods you could override - e.g. if you need to edit values in your grid you should probably set SimpleTypeValueUpdater as well.

Related

postsharp - Parameter value based caching

I am using the postsharp cache and I have created a sample function to cache the result of that - but I want to do caching based on parameter values only.
For example, my function looks like this
[Cache(SlidingExpiration = OneHour, IgnoreThisParameter = true )]
public IEnumerable<String> Get(int dateId)
{
// code processing
}
I want the output of this function to be cached if the dateid= T-1 (yesterday) and not when dateid is not T.
But with [Cache] attribute decorated, everything gets cached. Basically I want to cache T-1 data only and not data for any other dates.
This pattern is used so that we can invalidate the caches using custom methods but I dont see any option for selective parameter value based caching.
Can anybody respond to this?
Currently this is not possible. At this moment you need to split method into three methods and have:
public IEnumerable<string> Get(int dateId)
{
if (dateId == CurrentDate - 1)
GetCached(dateId);
else
GetCore(dateId);
}
[Cache(SlidingExpiration = OneHour, IgnoreThisParameter = true )]
private IEnumerable<string> GetCached(int dateId)
{
return GetCore(dateId);
}
private IEnumerable<string> GetCore(int dateId)
{
// ...
}
This is in the backlog, but it is not scheduled to any release at the moment.

How to retrieve data by property in Couchbase Lite?

My documents have the property docType that separated them based on the purpose of each type, in the specific case template or audit. However, when I do the following:
document.getProperty("docType").equals("template");
document.getProperty("docType").equals("audit");
The results of them are always the same, it returns every time all documents stored without filtering them by the docType.
Below, you can check the query function.
public static Query getData(Database database, final String type) {
View view = database.getView("data");
if (view.getMap() == null) {
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if(String.valueOf(document.get("docType")).equals(type)){
emitter.emit(document.get("_id"), null);
}
}
}, "4");
}
return view.createQuery();
}
Any hint?
This is not a valid way to do it. Your view function must be pure (it cannot reference external state such as "type"). Once that is created you can then query it for what you want by setting start and end keys, or just a set of keys in general to filter on.

My CellTable does not sort

I red a lot about sorting a CellTable. I also went trough the ColumnSorting with AsyncDataProvider. But my CellTable does not sort.
Here is my code:
public class EventTable extends CellTable<Event> {
public EventTable() {
EventsDataProvider dataProvider = new EventsDataProvider(this);
dataProvider.addDataDisplay(this);
SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
SimplePager pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 5, true);
pager.setDisplay(this);
[...]
TextColumn<Event> nameCol = new TextColumn<Event>() {
#Override
public String getValue(Event event) {
return event.getName();
}
};
nameCol.setSortable(true);
AsyncHandler columnSortHandler = new AsyncHandler(this);
addColumnSortHandler(columnSortHandler);
addColumn(nameCol, "Name");
getColumnSortList().push(endCol);
}
}
public class EventsDataProvider extends AsyncDataProvider<Event> {
private final EventTable eventTable;
public EventsDataProvider(EventTable eventTable) {
this.eventTable = eventTable;
}
#Override
protected void onRangeChanged(HasData<Event> display) {
int start = display.getVisibleRange().getStart();
int length = display.getVisibleRange().getLength();
// check false values
if (start < 0 || length < 0) return;
// check Cache before making a rpc
if (pageCached(start, length)) return;
// get Events async
getEvents(start, length);
}
}
I do now know, if all the methods are need here. If so, I will add them. But in short:
pageCached calls a method in my PageCache Class which holds a map and a list. Before making a rpc call, the cache is checked if the events where already taken and then displayed.
getEvents just makes an rpc call via asynccallback which updates the rowdata via updateRowData() on success.
My Table is displayed fast with currently around 500 entries (could be more, depends on the customer). No missing data and the paging works fine.
I just cannot get the sorting work. As far as I know, AsyncHandler will fire a setVisibleRangeAndClearData() and then an onRangeChanged(). onRangeChanged is never fired. As for the setVisibleRangeAndClearData() I do not know. But the sortindicator (arrow next to the columnname) does change on every click.
I do not want to let the server sort the list. I have my own Comparators. It is enough, if the current visible page of the table is sorted. I do now want to sort the whole list.
Edit:
I changed following code in the EventTable constructor:
public EventTable() {
[...]
addColumnSortHandler(new ColumnSortEvent.AsyncHandler(this) {
public void onColumnSort(ColumnSortEvent event) {
super.onColumnSort(event);
MyTextColumn<Event> myTextColumn;
if (event.getColumn() instanceof MyTextColumn) {
// Compiler Warning here: Safetytype unchecked cast
myTextColumn = (MyTextColumn<Event>) event.getColumn();
MyLogger.log(this.getClass().getName(), "asc " + event.isSortAscending() + " " + myTextColumn.getName(), Level.INFO);
}
List<Event> list = dataProvider.getCurrentEventList();
if (list == null) return;
if (event.isSortAscending()) Collections.sort(list, EventsComparator.getComparator(EventsComparator.NAME_SORT));
else Collections.sort(list, EventsComparator.descending(EventsComparator.getComparator(EventsComparator.NAME_SORT)));
}
});
addColumn(nameCol, "Name");
getColumnSortList().push(endCol);
}
I had to write my own TextColumn to determine the Name of the column. Otherwise how should I know, which column was clicked? The page gets sorted now but I have to click twice on the column. After then, the sorting is done with every click but in the wrong order.
This solution does need polishing and it seems kinda hacky to me. Any better ideas?
The tutorial, that you linked to, states:
This sorting code is here so the example works. In practice, you would
sort on the server.
Async provider is used to display data that is too big to be loaded in a single call. When a user clicks on any column to sort it, there is simply not enough objects on the client side to display "first 20 evens by name" or whatever sorting was applied. You have to go back to your server and request these first 20 events sorted by name in ascending order. And when a user reverses sorting, you have to go to the server again to get first 20 events sorted by name in a descending order, etc.
If you can load all data in a single call, then you can use regular DataProvider, and all sorting can happen on the client side.
EDIT:
The problem in the posted code was in the constructor of EventsDataProvider. Now it calls onRangeChanged, and the app can load a new sorted list of events from the server.

How to query data via Spring data JPA with user defined offset and limit (Range)

Is it possible to fetch data in user defined ranges [int starting record -int last record]?
In my case user will define in query String in which range he wants to fetch data.
I have tried something like this
Pageable pageable = new PageRequest(0, 10);
Page<Project> list = projectRepository.findAll(spec, pageable);
Where spec is my defined specification but unfortunately this do not help.
May be I am doing something wrong here.
I have seen other spring jpa provided methods but nothing are of much help.
user can enter something like this localhost:8080/Section/employee? range{"columnName":name,"from":6,"to":20}
So this says to fetch employee data and it will fetch the first 15 records (sorted by columnName ) does not matter as of now.
If you can suggest me something better that would be great.if you think I have not provided enough information please let me know, I will provide required information.
Update :I do not want to use native or Create query statements (until I don't have any other option).
May be something like this:
Pageable pageable = new PageRequest(0, 10);
Page<Project> list = projectRepository.findAll(spec, new pageable(int startIndex,int endIndex){
// here my logic.
});
If you have better options, you can suggest me that as well.
Thanks.
Your approach didn't work, because new PageRequest(0, 10); doens't do what you think. As stated in docs, the input arguments are page and size, not limit and offset.
As far as I know (and somebody correct me if I'm wrong), there is no "out of the box" support for what you need in default SrpingData repositories. But you can create custom implementation of Pagable, that will take limit/offset parameters. Here is basic example - Spring data Pageable and LIMIT/OFFSET
We can do this with Pagination and by setting the database table column name, value & row counts as below:
#Transactional(readOnly=true)
public List<String> queryEmployeeDetails(String columnName,String columnData, int startRecord, int endRecord) {
Query query = sessionFactory.getCurrentSession().createQuery(" from Employee emp where emp.col= :"+columnName);
query.setParameter(columnName, columnData);
query.setFirstResult(startRecord);
query.setMaxResults(endRecord);
List<String> list = (List<String>)query.list();
return list;
}
If I am understanding your problem correctly, you want your repository to allow user to
Provide criteria for query (through Specification)
Provide column to sort
Provide the range of result to retrieve.
If my understanding is correctly, then:
In order to achieve 1., you can make use of JpaSpecificationExecutor from Spring Data JPA, which allow you to pass in Specificiation for query.
Both 2 and 3 is achievable in JpaSpecificationExecutor by use of Pagable. Pageable allow you to provide the starting index, number of record, and sorting columns for your query. You will need to implement your range-based Pageable. PageRequest is a good reference on what you can implement (or you can extend it I believe).
So i got this working as one of the answer suggested ,i implemented my own Pageable and overrided getPagesize(),getOffset(),getSort() thats it.(In my case i did not need more)
public Range(int startIndex, int endIndex, String sortBy) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.sortBy = sortBy;
}
#Override
public int getPageSize() {
if (endIndex == 0)
return 0;
return endIndex - startIndex;
}
#Override
public int getOffset() {
// TODO Auto-generated method stub
return startIndex;
}
#Override
public Sort getSort() {
// TODO Auto-generated method stub
if (sortBy != null && !sortBy.equalsIgnoreCase(""))
return new Sort(Direction.ASC, sortBy);
else
return new Sort(Direction.ASC, "id");
}
where startIndex ,endIndex are starting and last index of record.
to access it :
repository.findAll(spec,new Range(0,20,"id");
There is no offset parameter you can simply pass. However there is a very simple solution for this:
int pageNumber = Math.floor(offset / limit) + ( offset % limit );
PageRequest pReq = PageRequest.of(pageNumber, limit);
The client just have to keep track on the offset instead of page number. By this I mean your controller would receive the offset instead of the page number.
Hope this helps!

Exporting a filtered Grid data In Telerik RadGrid

When exporting a rad grid data if the user has it filtered in any way the grid should just export the filtered data not the entire dataset - Any idea how to achieve this?
Regards - Hemant
Here is a solution that allows one to get a filtered, sorted list of data items using the current filter and sort settings from a Telerik RadGridView control (Silverlight version).
using Telerik.Windows.Data;
.
.
.
IEnumerable<MyClass> itemsToDisplay { get; set; } //The RadGridView is bound to this property
public void DoSomethingWithFilteredAndSortedDisplayItems(RadGridView rgv)
{
IQueryable<MyClass> iqItems = itemsToDisplay.AsQueryable();
FilterDescriptorCollection filter = rgv.FilterDescriptors;
SortDescriptorCollection sort = rgv.SortDescriptors;
List<MyClass> fsItems = iqItems.Where(filter).Sort(sort).ToIList() as List<MyClass>;
if (fsItems != null && fsItems.Count > 0)
{
DoSomethingWithDisplayItems(fsItems);
}
}
public void DoSomethingWithDisplayItems(IEnumerable<MyClass> list)
{
... //Do something
}
I think that if you assign the filtered set of data to the grid before calling the export method (which internally rebinds it), you will get the filtered values in the exported file.

Resources