vaadin flow 23 - in memory gird sort not working - sorting

I'm trying allow a user to sort the grid by a column who's value is derived:
grid.addColumn(Category::getPath).setHeader("Path");
grid.addColumn(category -> getCount(category))
.setHeader("Packages")
.setComparator((a,b) -> orderByCount(a, b));
private int orderByCount(Category a, Category b)
{
Long acount = daoCategoryPackage.getCount(CategoryPackage_.category, a);
Long bcount = daoCategoryPackage.getCount(CategoryPackage_.category, b);
return acount.compareTo(bcount);
}
The grid shows the 'sort' icon in the header and I can click the icon and it changes state (up arrow, down arrow, both arrows).
If I trace the code I can see that the grid attempts a sort as 'Grid:setSortOrder' is called and the columnKey in GridSortOrder is correct (col1).
However the orderByCount method is never called.
It feels like I need to add some other setting to the grid but the documentation makes no suggestion and looking at the api I can see anything obvious.

It's not possible to know without seeing more of the code, but the problem is likely that you're using a lazy-loading dataprovider, which can't handle a comparator provided like that. If you look at the method's JavaDoc, you'll see:
Sets a comparator to use with in-memory sorting with this column. Sorting with a back-end is done using setSortProperty(String...).

Related

Apply a sort to a dataset in a PowerApps component (PCF)

I’m trying to create a new dataset type Powerapps Component (PCF). For the moment I am using it to display a view of the records that are available in an entity in Microsoft Dynamics CRM.
I wish to make the view sort itself when I click on the grid column headers (in a similar way that the default CRM grid view does). I'm trying to figure out how to apply a sort to the dataset so that I can refresh it as indicated by the documentation for the dataset.refresh() function:
Refreshes the dataset based on filters, sorting, linking, new column.
New data will be pushed to control in another 'updateView' cycle.
The dataset object does have a “sorting” property, but changing its value and then refreshing the dataset doesn’t seem to have any effect. After the refresh, the sorting property reverts to the value it had before I changed it.
In short, the click handler for the grid header does something like the following bit of code. The refresh gets done and my updateView() function gets called as expected but the sorting was not applied.
dataset.sorting = [{name: 'createdon', sortDirection: 1}];
dataset.refresh();
Any help on getting the dataset sorting to work would be appreciated.
I've been experimenting with PowerApps Component Framework a little bit recently and I can confirm that the following code won't be working:
dataSet.sorting = [ { name: "columnName", sortDirection: 0 } ];
However, I managed to get this one working for me:
dataSet.sorting.pop(); // you may want to clean up the whole collection
dataSet.sorting.push({ name: "columnName", sortDirection: 0 });
I haven't really figured out the reason of this behavior. The sorting array may be implemented as some form of observable collection in the background.
I hope this will guide you to a functioning solution.
The documentation is pretty abysmal here, but here is my best guess from putting a few different pieces of information together.
TLDR: I think there is some kind of extra method that needs to be called on the .sorting property, but I can't find out what it is called. Maybe something like:
dataset.sorting.setSorting({name: 'createdon', sortDirection: 1});
I think you're going to have to try a bunch of likely method names and see what works.
Background and links:
The only reference I could find to dataset.sorting was from here:
In this preview for canvas apps, only a limited set of filtering and sortStatus methods are supported. Filter and sort can be applied to dataset on primary type columns except for the GUID. Filter and sorting can be applied in the same way as in model-driven apps.To retrieve the dataset with filtering and sorting information, call
the methods in context.parameters.[dataset_property_name].filtering
and context.parameters.[dataset_property_name].sorting, then invoke
the context.parameters.[dataset_property_name].refresh().
So it seems that the .filtering and .sorting properties are handled similarly, and that there are some methods attached to them, and only some are supported. That is about as vague as they could make it...
I did find an example of how .filtering is used:
_context.parameters.sampleDataset.filtering.setFilter({
conditions: conditionArray,
filterOperator: 1, // Or
});
There is a brief reference to .setFilter() in the docs, as well as FilterExpression
There is a SortStatus reference, but it doesn't have any corresponding methods explicitly called out. It is possible that this is not yet a supported feature in the public preview, or the documentation is lacking and the name and syntax of the method you need to call on .sorting is not yet documented.

AngularDart custom filter call() method required to be idempotent?

The main running example of the Angular Dart tutorial is a Recipe Book app. The exercise at the end of the Chapter 5 on filters and services suggests trying to "create a [custom] filter that will multiply all the amounts [of each ingredient listed] in the recipes" thus allowing a "user to double, triple, or quadruple the recipe." E.g. an ingredient of "1/2 cup of flour" would become "1 cup of flour" when doubled.
I have written such a custom filter: it takes a list of Ingredients (consisting of a quantity and a description) and returns a new list of new Ingredients (with increased quantities), but I am getting the following error:
5 $digest() iterations reached. Aborting!
My question is: what is the required and/or permitted behavior of an AngularDart custom filter call() method? E.g., clearly it is permitted to remove (i.e. filter) elements from its input list, but can it also add new or replace elements? The Dart angular.core NgFilter documentation simply says that a "filter is a class with a call method". I have not found more details.
Extrapolating from the answer to this AngularJS post, it would seem that repeated invocations of call() should (eventually?) yield "the same result". If so, this would be a reasonable constraint.
Yielding "the same result" could mean that call() needs to be idempotent, but in the case of Dart such idempotence should be relative to == (object equivalence) not identical() (object identity), IMHO. I ran a few tests using the following small example to illustrate the issues:
main.dart
import 'package:angular/angular.dart';
class A { }
#NgFilter(name:'myFilter') class MutatingCustomFilter {
final A _a = new A();
call(List list) => new List.from(list)..add(_a); // runs ok.
// call(List list) => new List.from(list)..add(new A()); // gives error
}
class MyAppModule extends Module {
MyAppModule() { type(MutatingCustomFilter); }
}
main() => ngBootstrap(module: new MyAppModule());
index.html excerpt
<ul>
<li ng-repeat="x in [1,2,3] | myFilter">{{x}}</li>
</ul>
If I change the body of class A to be
#override bool operator==(other) => true;
#override int get hashCode => 1;
which makes all instances of A considered ==, then the second implementation of call() in main.dart (the one with add(new A())) still gives an error (though a different one).
I can see how to solve the tutorial exercise without use of a custom filter, but I am trying to not give up on the challenge of finding a filter that will work as requested. I am new to Angular and decided to jump in with AngularDart, so any help in explaining the effects of the various flavors of call(), or in finding documentation for the expected behavior of call(), (or letting me know if you think such a custom filter simply cannot be written!) would be appreciated.
Too many iterations
When angular detects a change in the model, it executes a reaction function. The reaction function can further change the model. This would leave the model in inconsistent state. For this reason we re-run the change detection, which can further create more changes. For this reason we keep re-running the changes until the model stabilizes. But how many times should we rerun the change detection before giving up? By default it is 5 times. If the model does not stabilize after 5 iteration we give up. This is what is going on in your case.
Change Detection
When has object changed? one can use identical or == (equals). Good arguments can be made for each, but we have chosen to use identical because it is fast and consistent. Using == (equals) is tricky and it would negatively impact the change detection algorithm.
Filters and arrays
When a filter which operates an an array, executes it has no choice but to create a new instance of the array. This breaks identical, but luckily it is fed into ng-repeat which uses its own algorithm for array contents detection rather the array detection. While the array does not have to be identical between runs, its content must be. Otherwise ng-repeat can not tell the difference between insertions and changes, which it needs to do proper animations.
Your code
The issue with your filter is that it creates new instance on each iteration of the digest loop. These new instances prevent the model from stabilizing and hence the error. (There are plans to solve this issue, but it will be few weeks before we get there.)
Solution
Your solutions is attempting to create a filter which consumes the whole array and then attempts to create a new array, for the ng-repeat. A different (prefered) solution would be to leave the ng-repeat iteration as is, and instead place the filter on the binding which is creating the qty and apply it there.
<span>{{recipe.qty | myFilter:multiply}}</span>

Linq lazy loading, (EF Code first, Web.API and MVC)

I am having an odd problem with data loading which I don't understand, and I am hoping someone can explain to me what is going on, and perhaps how to accomplish my task more directly.
I am building a website using the technologies listed in the subject of this question.
I have a set of objects - each object has several properties (Name, ID, etc.) and a collection (ICollection<>) of other objects. So just looking at the tree of objects and their collections, it looks like this:
Tab
-TabRows
--Sections
---SectionRow
----Article
(So each tab has one or more tabrows, each tabrow has one or more sections, and so on. Each sub-object has a link back the parent, so each sectionrow has a SectionID, each Section has a TabRowID, etc.)
OK, so given that structure, consider this code:
// GET api/Tab/5
public Tab GetTab(int id)
{
var tab = db.Tabs.FirstOrDefault(t => t.TabId == id);
var tabrows = db.TabRows.ToList();
var sections = db.Sections.ToList(); // This makes the tabRow.Sections populate
var sectionrows = db.SectionRows.ToList();
var articles = db.Articles.ToList();
return tab;
}
So here is what happens. When the first line (var tab =...) executes, I get a tab object, but the TabRows collection is empty. (It is not null because the constructor instantiates it).
When the second line (var tabrows =...) executes, tab.TabRows suddenly populates. tab.TabRows.Sections is empty.
When the third line executes, tab.TabRows.Sections suddenly populates.
And so on.
I am assuming this is some sort of "lazy loading" on behalf of Linq, or perhaps one of the other technologies. But I don't know them well enough to figure it out.
Is there a way to re-write this so that I can just call line 1 and basically have everything auto-populate without having to individually reference every single object in every single collection?
Lazy loading is enabled by default and eager loading disabled. Entity framework allows you to hint at eager loading using the include statements. Your statement will become something like this.
var tab = db.Tabs.FirstOrDefault(t => t.TabId == id).Include("TabRows");
or as Include(t => t.TabRows);
Take a look at this link for more information.
In your case you would need to handle nested includes as well. Which means you would be better off taking another Model (your class) structured as follows
Tabs -> Containing a List<TabRows> -> containing a List<Sections> etc.
You would then need to re-write the linq so it populates the entire Model including the nested entities using nested includes.
As a side note, too many of these inner joins might slow down your querying and so consider indexed views on your DB side if and when possible

Qt: Using default model for selecting my data

I am quite new to Qt and am in a situation where I want to use a model for my needs:
I have a dynamic number of instances of a subclass that need to be handled differently (different UI controls for each if it is selected). I want to get a list view where I can add new elements or delete old ones, as well as disabling/enabling existing ones.
Of course I want to rewrite as least of the code as possible, so I thought of utilizing the Listwidget and a ListModel to give some controls to the user. But how to link these (or better the items) to instances of the classes?
Do you know any tutorials on this?
I already looked in QtDemo and Google but I do not know the right words to search for
so I had no good results.
Basically what I think I need is a model item that accepts Collider* for its data.
But when I plug this into QStandardItem.setData() it says error: ‘QVariant::QVariant(void*)’ is private
So I found the solution to this problem.
As QStandardItems are capable of storing QVariants as data I wanted to store a pointer to my data in a QVariant. To achieve this I had to use Q_DECLARE_METATYPE(MyType*).
With this I was able to
MyType *MyInstance = new MyType;
QVariant data;
data.setValue(MyInstance);
QStandardItem *item = new QStandardItem("My Item");
item->setData(data);
standardModel->appendRow(item);
And the best is you can add as many types you want and let QVariant do the work to decide if it contains the type you wanted:
if(v.canConvert<MyType*>())
//Yes it is MyType
else if( v.canConvert<MyOtherType*>())
//Oh it is the other one
So finally this only requires to declare the meta type so you do not have to subclass any items.
Also you should read on the limitations of this here:
Q_DECLARE_METATYPE
qRegisterMetaType
Does this page answer your questions? There's an example of deriving a StringListModel item that you might be able to use as a template

Simple hierarchical listing in PyQT

I'm trying to create a UI with 3 columns - when you select an item in the left column, the select item is passed to a function, and it returns the items for the middle column (and of course same for selecting items in the middle column)
Should be simple, but I can't find any easy way to do this..
I first tried QColumnView, as it seemed perfect.. however implementing the QAbstractItemModel seems excessively complicated, and I couldn't find any useful examples of this.
Next, since there is a fixed number of levels, I made three QListView, and modified this example QAbstractListModel
..however there seemed to be no useful signal I could use to trigger the updating of the other levels of the hierarchy. According to the PyQT docs, QListView only has the "indexesMoved" signal. There is also "clicked" and "pressed", however these didn't trigger when changing items with the keyboard
The last options is QListWidget, which would work as it has the required signals (itemChanged etc), but the way list items are created is a bit tedious (making QListWidgetItem with the parent set to the QListWidget instance)
Edit: QListWidget does pretty much what I need:
self.first_column = QListWidget()
self.first_column.itemSelectionChanged.connect(self.update_second_column)
Any QAbastractItemView has a QItemSelectionModel accessible via the selectionModel method.
The QItemSelectionModel has signals that may help you:
currentChanged ( const QModelIndex & current, const QModelIndex & previous )
currentColumnChanged ( const QModelIndex & current, const QModelIndex & previous )
currentRowChanged ( const QModelIndex & current, const QModelIndex & previous )
selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected )
Hope it helps.
QListView inherits from QAbstractItemView (I think you knew this), so it gets a few signals, hopefully one (or a few) of them works for you.
This is working for me (connect signals when initializing your QMainWindow or main QWidget, as in the SaltyCrane example):
connect(your_list_view, SIGNAL("clicked(const QModelIndex&)"), handler_slot)
...
def handler_slot(idx):
#idx is a QModelIndex
#QModelIndex.data() returns a QVariant, Qt4's generic data container
celldata = idx.data()
#Choose the proper datatype to ask the QVariant for (e.g. QVariant.toInt())
actualvalue = celldata.toInt()
#QVariant.toInt() happens to return a tuple
print actualvalue[0]
Depending on the type of data in your model, you'll want to choose the right data type to ask QVariant for.
The sneaky part here is getting the QListView to tell you which cell was clicked (i.e. using clicked(const QModelIndex&) vs clicked()). I think I spent some time looking at the C++ documentation for Qt4 before I realized you could get more out of the signals.
From here, I would have the handler_slot() call a setData() method on the model for your second QListView (using data generated by the function you originally planned to use).
I'd be glad to elaborate if I haven't quite answered your question.
Edit: Working with arrow keys
Hmm, it seems weird that there isn't a default QListView signal for arrow movement, but we can make our own.
(This almost seems out-of-style for Qt4's signals and slots modus operandi)
QListView reimplements a method keyPressEvent(self, QKeyEvent) which acts as a callback function when certain keys are pressed. You can read more. We can use this to grab the keyevent(s) that we want, and emit our own signal.
class ArrowableListView(QListView):
def keyPressEvent(self, keyevent):
#Maintain original functionality by calling QListView's version
QListView.keyPressEvent(self, keyevent)
#QListView.selectedIndexes returns a list of selected cells, I'm just taking the first one here
idx = self.selectedIndexes()[0]
#We'll emit a signal that you can connect to your custom handler
self.emit(SIGNAL("my_signal"), idx)
Once a keypress occurs, we ask the QListView what the selected indices (!) are. Of course, you can choose to filter out certain keys and choose whether to handle multiple selected cells (I think you can set a selection mode where this isn't possible, see QListView documentation).
Now that we have the selected indices (list of QModelIndex), we pass the first one (a QModelIndex) along with our signal. Because we're defining this signal in python, we don't have to set a function prototype; I have no idea if this is bad style.
Now all you have to do is connect the signal to a handler:
self.connect(your_list_view, SIGNAL("my_signal"), handler_slot)
and write your handler.
I hope this isn't too nasty of a workaround.

Resources