Closed MitchellNZ closed 2 years ago
@stsrki I ended up creating my own example of this here: https://github.com/MitchellNZ/Blazorise/commit/150c1152326a470e26315426d6f604e33d0435a8
This just allows me to write something like
<DataGridNumericColumn ... SortValue="(x) => x.Guilds.Count">
I haven't made a pull request, as I'm not sure if you can already do this some other way - or you had a different preferred option. Please let me know if you have other suggestions.
I would probably go with the same route as current Field
property and create a new SortField
. The reason is that this new field also have to have precompiled getter so there is no bottlenecks. The usage in code-behind would be similar to the one you already started.
@stsrki thanks for the reply.
With going the same route as the Field
attribute being a precompiled getter, would it be possible to still do something like I’ve done with the list.Count
?
Or would you recommend adding the count as a int
to my model?
Doing it with an expression predicate like in your example is easier at first. But the problem is it won't work with the dynamic ReadData
event when it's connected to the outside data API.
Oh I see. Thanks for the explanation.
I haven't looked into ReadData
much yet. But I will be needing large data reading functionality soon, so I will take a look!
I am starting work on this... I think @MitchellNZ hit the spot. Just introduce a SortExpression
which is handled by Blazorise for static data. Otherwise, for ReadData
we already make the user have to handle the sorting.
So the info about the SortExpression
is passed on to the User, he should then handle it accordingly like it already happens with regular sorting. There's not much more we can do about it I guess. Right?
@David-Moreira Doing it with the expression would make it impossible with large data and a ReadData
callback. How to pass an expression to the backend API?
The best way would be to add SortField
. It would behave the same as Field
. If defined it would override it when sorting. That's it.
I don't like that at all... A string? While a property accessor is kinda straightforward an expression of a Func<TItem, Object> is not... I doubt people would be enticed to pass an expression string to their api... I personally would probably cheat and send an identifier that tells me which type of sort to apply.
Even for normal use in static data that seems ugly?
In my opinion I'd like to give the users the intelisense from expression.
Ahh I was thinking...
Now I understand what functionality for sorting you were thinking.. Just straight up property / field accessor... OK, I wouldn't mind a string there.
I was thinking in more flexibility sorting by proving a Func with the TItem, the user could do a lot more. But the first one is actually better for compatibility with both static and readdata I guess...
Now I understand what functionality for sorting you were thinking.. Just straight up property / field accessor... OK, I wouldn't mind a string there.
Yes, and internally it would still compile through the same getter expression builder.
We could add expressions with the signature Func<TItem, Object>
for Field
and SortField
. But then there is another problem that I realized. We would have to also have the setters. Remember that we have an edit mode that needs to properly update TItem. In the end, we would have 6 APIs. Not sure if it's worth it.
Intelisense would be pretty... but nAAAAAAh not worth it, haha unless heavily requested. Going with the first option.
What SortField i should specify for example for the following case:
<DataGrid TItem="OrderItem" Data="orderItems" Sortable ShowCaptions>
<DataGridColumns>
<DataGridColumn Field="@nameof(OrderItem.Product)" Caption="Name">
<DisplayTemplate>
@context.Product.Name
</DisplayTemplate>
</DataGridColumn>
<DataGridNumericColumn Field="@nameof(OrderItem.Quantity)" Caption="Count">
<DisplayTemplate>
@context.Quantity
</DisplayTemplate>
</DataGridNumericColumn>
</DataGridColumns>
</DataGrid>
In this case at sort by the 'Name' column i get the error:
System.InvalidOperationException
Inner Exception: ArgumentException: At least one object must implement IComparable.
(sure, because the 'Product' class don't have a comparer)
Where 'OrderItem' is DB entity and i don't want define something like a ViewModel for one.
The mentioned 'SortExpression' would solve this issue.
Field="@nameof(OrderItem.Product)"
Isn't Product a class or record? Why are you not binding the name?
Field="Product.Name"
David-Moreira, How to binding?
SortField="@nameof(OrderItem.Product.Name)"
?
But the 'Name' is not property of 'OrderItem'
where we have: <DataGrid TItem="OrderItem" Data="orderItems">
I used well known classes, but here are their cropped definitions for more clarity:
class OrderItem
{
public Product {get; set;}
public int Quantity {get; set;}
}
class Product
{
public string Name {get; set;}
}
Hello,
nameof() extracts the name of whatever field or property is indicated. So it will yield "Name" in your case. Which is not the correct path to get to the Product Name. Therefore the error : "But the 'Name' is not property of 'OrderItem'" as it's trying to look that field up directly in OrderItem
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof
Since you have to "traverse a path" to get yo your path name you need to do something like : SortField="Product.Name"
Please let us know if this helped you.
David-Moreira, Sorry for delay.
Of course, I understand all this initially.
That's why early I mentioned the proposed 'SortExpression' field that can solve this issue (as a variant).
But I was hoping that you have some alternative way for such cases (wrapping by something like a ViewModel is bad variant for me, my real case much more complicated).
So, as far as I understand, the Blazorise does not have a direct solution to this issue. And may be this can be a feature request?
Indeed the Blazorise DataGrid have custom filtration,
have custom calculated column (<DisplayTemplate>
),
but haven't custom sorting opportunities (for the same custom calculated column).
What do you mean does not have a direct solution?
SortField="Product.Name"
should work and properly sort your data. Or am I miss understanding your requirement?
I'll give the whole code (simplified of course):
class OrderItem
{
public Product {get; set;}
public int Quantity {get; set;}
}
class Product
{
public string Name {get; set;}
}
<DataGrid TItem="OrderItem" Data="orderItems" Sortable ShowCaptions>
<DataGridColumns>
<DataGridColumn Field="@nameof(OrderItem.Product)" SortField="@nameof(Product.Name)" Caption="Name">
<DisplayTemplate>
@context.Product.Name
</DisplayTemplate>
</DataGridColumn>
<DataGridNumericColumn Field="@nameof(OrderItem.Quantity)" Caption="Count">
<DisplayTemplate>
@context.Quantity
</DisplayTemplate>
</DataGridNumericColumn>
</DataGridColumns>
</DataGrid>
When I try to sort by the "Name" column I get the exception (see the screenshot):
As far as understand it's because the "Name" is not a member of the "OrderItem" class.
additional info (if it matters): used Blazorise version - 1.5.0 my project - net8 sorting by the "Quantity"("Count") column - ok
the <DataGrid TItem="OrderItem"..>
(OrderItems.razor component) placed as <DetailRowTemplate>
into another DataGrid as:
<DataGrid TItem="Order" Data="@ordersList"..>
..
<DetailRowTemplate>
<OrderItems OrderItemsCollection="context.Items" />
</DetailRowTemplate>
..
</DataGrid>
where:
class Order
{
..
public ICollection<OrderItem> Items {get; set;}
}
Field="@nameof(OrderItem.Product)" SortField="@nameof(Product.Name)"
I'm sorry but I just told you, that you are missusing nameof in this case.
This snippet is incorrect given your model:
Field="@nameof(OrderItem.Product)" SortField="@nameof(Product.Name)"
You need to tell the DataGrid the correct path.
Again, please try this.
Field="Product.Name" SortField="Product.Name"
Mea Culpa! Sorry, Sorry, Sorry! I was inattentive. I thought that the "Field/SortField" is just a field name, but not a full path to field. And thank you very much for your patience and help.
Mea Culpa! Sorry, Sorry, Sorry! I was inattentive. I thought that the "Field/SortField" is just a field name, but not a full path to field. And thank you very much for your patience and help.
Haha no problem. It's ok. Glad you got it working!
Firstly, sorry for opening so many issues lately, I'm just starting to use this quite heavily! This is more of a question, possibly feature request.
Question: With the DataGrid, is it possible to configure the columns Field attribute to handle a List.Count? If not, is it possible to override with a custom sort function to enable ability to sort by a lists count?
Currently I am doing the following to display a list count in a column:
Thanks again!