Hi,
I have a MultiSelect with my CustomDataAdaptor to access a remote data source that can have thousands of product items where the API returns pages with a maximum of 50 records.
The control does the search properly, displays the selected items on chips with the Product Description (VisualMode.Box), is limited to select a maximum of 50 items, and is working fine.
The point is, this selection needs to be saved for later use or review. So I need a way to bring this control already populated with that selection, as if it were in the "same state" as when the initial selection was made and still allow the user to search and make new selections.
As the saved selection can have products located in any "API page", I know that when initializing the DataSource I need to bring all selected Ids from the API, allowing the control to correctly display the chips with the descriptions of the selected products..
I used the Query property with a WhereFilter with the list of Ids to bring from the API only the records previously selected in the component's initialization and it worked well too.
Okay, now I just need to clear this WhereFilter to allow the user to access all other products to be able to make new selections.
The problem is that this forces the DataSource to reload and clears my selection.
I tried using the Custom FIlter (below) to update my _query property in the new search, however a "new Query()" clears the current selection.
private void onFilter(FilteringEventArgs args)
{
args.PreventDefaultAction = true;
var query = new Query().Search(args.Text, new List<string> {"Description"});
_query = string.IsNullOrEmpty(args.Text) ? new Query() : query ;
}
Setting the Query property to null didn't work either.
Could you please guide me on how to achieve this goal?
Thanks,
Sergio Sant'Anna
private void onFilter(FilteringEventArgs args)
{
args.PreventDefaultAction = true;
var query = new Query().Search(args.Text, new List<string> {"Description"});
_query = string.IsNullOrEmpty(args.Text) ? new Query() : query ;
}
|
Hi,
Thanks for the feedback, but maybe I can't make myself understood.
As I mentioned, I had already tried both situations. Creating a new instance (new Query()) or assigning null has the same unwanted effect and clears my selection.
How to change my WhereFilter clause and keep previous selection?
Regards,
Sérgio Sant'Anna
<SfMultiSelect TValue="string[]" TItem="Countries" Placeholder="e.g. Australia" DataSource="@Country" HideSelectedItem=false>
<MultiSelectFieldSettings Text="Name" Value="Code"></MultiSelectFieldSettings>
</SfMultiSelect> |
Hi,
Thanks for the feedback, but changing the HideSelectedItem property didn't cause any change in my case.
The documentation for this property is vague and just says "Hides the selected item from the list item", which doesn't really explain what behaviors are changed.
Here's my component code:
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.DropDowns
<SfMultiSelect @ref=@_multiSelectRef
TValue="string[]"
TItem="ProductDto"
Query=@_query
@bind-Value=@Value
AllowFiltering="true"
HideSelectedItem="false"
Placeholder="Products"
FilterBarPlaceholder="Search"
[email protected]
FloatLabelType="FloatLabelType.Auto"
EnableSelectionOrder="false"
ShowDropDownIcon="true"
PopupHeight="350px"
CssClass="e-outline e-multi-column">
<SfDataManager Adaptor="Adaptors.CustomAdaptor">
<MyProductDataAdaptor />
</SfDataManager>
<MultiSelectTemplates TItem="ProductDto">
<HeaderTemplate>
<table>
<tr>
<th class="e-text-left" width="30px">Id</th>
<th width="250px">Description</th>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<div>
<table>
<tbody>
<tr>
<td class="e-text-left" width="30px">@((context).Id)</td>
<td width="250px">@((context).Description)</td>
</tr>
</tbody>
</table>
</div>
</ItemTemplate>
</MultiSelectTemplates>
<MultiSelectFieldSettings Text="Description" Value="Id" />
<MultiSelectEvents TValue="string[]" TItem="ProductDto"
ValueChange=@onValueChanged
DataBound=@onDataBoundHandler />
</SfMultiSelect>
@code
{
private Query? _query;
private bool _firstExecution = true;
private SfMultiSelect<string[], ProductDto> _multiSelectRef = default!;
[Parameter] public string[]? Value { get; set; }
[Parameter] public EventCallback<string[]> ValueChanged { get; set; }
protected override void OnParametersSet()
{
base.OnParametersSet();
if (Value is not null && Value.Any())
{
var whereFilters = new List<WhereFilter>();
foreach (var id in Value)
{
whereFilters.Add(new() { Field = "Id", Operator = "equal", value = id });
}
_query = new Query().Where(whereFilters).Take(50);
}
else
{
_query = new Query().Take(10);
}
}
private async Task onValueChanged(MultiSelectChangeEventArgs<string[]> args)
{
await ValueChanged.InvokeAsync(args.Value);
}
private void onDataBoundHandler(DataBoundEventArgs obj)
{
if (_firstExecution)
{
_firstExecution = false;
_query = new Query();
//_query!.Queries.Where = new List<WhereFilter>();
}
}
}
My previous selection is still cleared when I assign a new instance to the Query property. Line:
_query = new Query();
The closest I got to achieving my goal was cleaning up the Where filters, replacing the new Query() with this line:
_query!.Queries.Where = new List<WhereFilter>();
But now only selected items are displayed when the popup is opened by mouse click and I can only see the other items if I start typing.
This behavior is different from when I make my initial selection.
How can I resolve this last point? Is there a better way to reach my goal?
Regards,
Sérgio Sant'Anna
Hi Berly Christopher,
Thanks for the most complete example. I made some modifications and was able to reproduce exactly the issues I am reporting.
Think of a use case where a user has a Form and makes some selections, saves it, and then can modify it later.
The main modification was to reproduce the selection behavior when initializing the control with a previous selection that has items located on different 'pages' of the remote result.
In this modified example, there are now a total of 1000 items, and I also use two instances of the same control, the first without a pre-existing selection and the other with a previous selection on items: 2, 51, 101, 552 and 905.
My goal is to get both instances to behave exactly the same, when performing basic control tasks like: displaying available items in the popup, searching, modifying the existing selection, or when the selection is cleared and I redo one from the beginning.
The main difference in behavior can already be seen when clicking to open the popup with available items. In the control with pre-selection only selected items are displayed and if the selection is cleared by the X button, when clicking again on the popup no available items are displayed.
To explore other differences, try to start manually selecting the same 4 items in the first instance and after selected, browse both components and you can see the behavior differences in the display of items available in the popups.
Could you please guide me on how I can resolve these issues and achieve these goals?
Regards,
Sérgio Sant'Anna
Hi Berly,
Thanks for the feedback. Maybe it's a language issue and I'm sorry if I didn't make myself understood. Because I believe I've been sharing my requirements in a lot of detail.
Let's try again.
The use case for changing the query property in the DataBound is that after initializing the control already populated with the previous selection, I need to clear this initial query to allow the user to browse and select any other of the 1000 Products in this example.
I used OnParametersSet because it was also how I could make the control keep the selection after changing the query property in onDataBoundHandler. Doing the same using your OnAfterRender suggestion will clear the previous selection. Uncomment my code in onDataBoundHandler and you will see this behavior.
Another unwanted behavior in this modified code is that it is now not possible to select more items in the second control with pre-selection, which also does not meet what I explained earlier in the paragraph:
"The point is, this selection needs to be saved for later use or review. So I need a way to bring this control already populated with that selection, as if it were in the "same state" as when the initial selection was made and still allow the user to search and make new selections."
It also changed the behavior in the first control without pre-selection, now when you click to open it without typing a search the popup opens with "No Records Found".
Regards,
Sérgio Sant'Anna
<SfMultiSelect ID="Dropdown1" TValue="int[]" TItem="WeatherForecast" Query="Query" @bind-Value="@MultiVal" PopupHeight="150px" EnableVirtualization="true">
<SfDataManager @ref="dataManagerObj" AdaptorInstance="@typeof(CustomAdaptor)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager>
<MultiSelectFieldSettings Value="ID" Text="Summary"></MultiSelectFieldSettings>
</SfMultiSelect>
@code{
//Custom adaptor
SfMultiSelect<int[], WeatherForecast> MultiselectObj;
SfDataManager dataManagerObj;
public int[] MultiVal { get; set; } = new int[] { 1001, 1004, 1008};
public Query Query = new Query().Take(6);
|
Hi Ponmani,
Thanks for the feedback, but unfortunately this proposal doesn't reflect my use case and I can't understand how this meets my original request.
We've had several iterations and in the last few we've come very close to solving the problem. We arrived at this using a code I submitted on Dec 22-2021 that shows exactly my use case and the problem I faced.
Could you please analyze it in more depth and propose a new solution by modifying this sample I sent?
Regards,
Sérgio Sant'Anna
Hi,
Any updates on this?
Regards,
Sérgio Sant'Anna
public void onFocus()
{
_query = new Query().Where(new WhereFilter());
} |
public override object Read(DataManagerRequest dataManagerRequest, string key = null)
{
try
{
var req = (dataManagerRequest == null) ? "null" : Newtonsoft.Json.JsonConvert.SerializeObject(dataManagerRequest);
System.Diagnostics.Debug.WriteLine("Reading custom adaptor. Key is " + key + ", req: " + req);
int count;
if (dataManagerRequest.Take != 0) {
count = dataManagerRequest.Take;
} else
{
count = 1000;
}
} |
Hi Ponmani,
Thanks for the feedback, but unfortunately none of the suggestions are applicable.
Using 'EnablePersistance' doesn't suit me because the previous selection comes from a database and it will be different depending on the user's choice.
The suggested use of 'Focus' creates a side effect in the control that clears selected items only from the screen. Maybe you didn't notice this in your example. And finally, modifying Take to send all items is not a viable option for my API with thousands of records.
I'll try to explain my use case another way, and maybe you have some other suggestion:
I have a CRUD form like any other, with SfTextBoxes, Checkboxes and etc. and also with some of these SfMultiselects. Like any form editing action, all these controls must already appear populated for a user to make changes.
The difficulty is to initialize the SfMultiselect with the proper selections when this control depends on a paged RestAPI data source with thousands of records.
The million dollar question is: How can I initialize this control correctly displaying the 'chips' with the descriptions of the selected items as happens in a fresh selection?
I attached another example code with 3 instances of SfMultiselect that shows the 3 possibilities I need to make it behave the same way.
#1 - Multiselect control initializes without any selection.
#2 - Multiselect control initializes with 3 pre-selected items;
#3 - Multiselect control initializes without any selection, but interactively loads the selection of 2 items when clicking a 'Load Selection' button.
Please do the steps below:
1st - In instance #1, manually select 3 items. For example: #5, #50 and #505.
2nd - In instance #3, click on the Load Selection button. Once items #3 and #303 have been populated, try adding item #305.
3rd - In instance #2 try to select item #505.
What is desired is that instances 2 and 3 behave exactly the same as the first instance in step 1. (open popup on click, display available items, allow selecting new items, etc.).
You will see that changing the selection in one of the instances interferes with the functioning of the others, and also that the control stops behaving as expected in all of them.
Please see if you can achieve the expected behavior and if possible modify my example with such tweaks.
Regards,
Sergio Sant'Anna
Hi Ponmani M,
Thanks for the feedback, but due to the lack of SfMultiselect features for advanced scenarios like this, we developed our own component.
Regards,
Sergio Sant'Anna