FlutterArtist Sort DropdownSortPanel Example
Sorting involves arranging data in a specific order, such as ascending or descending, based on one or more criteria. In applications, sorting can be performed on the client-side or server-side, or even both, each with its own advantages and limitations.

Server-side Sorting
Server-side sorting involves sending a request to the server to perform the sorting operation. The server processes the data (usually via database queries) and returns the sorted results to the client. If the request includes pagination, the data received will vary depending on the sorting criteria.

Client-side Sorting
Client-side sorting involves arranging data already available on the client (previously fetched from the server). The data itself doesn’t change; only the order changes according to the selected criteria.
No ADS

FlutterArtist supports both server-side and client-side sorting. You provide a SortModelBuilder to define the criteria and rules for client-side sorting. SortModelBuilder is used to create two SortModel objects, one used for server-side sorting, the other used for client-side sorting.
- ServerSide-SortModel: Provides criteria for the server to perform sorting (e.g., by price or stock quantity). Through the SortPanel, users select their preferred criteria and direction.
- ClientSide-SortModel: Provides a list of criteria and data comparison rules (by implementing the abstract methods of the SortModelBuilder).
Chú ý, nếu bạn không muốn sử dụng SortModel cho máy khách, người dùng có thể tự sắp xếp các ITEM(s) một cách thủ công thông qua việc kéo thả trên giao diện. Chẳng hạn các ví dụ sau:
Trong bài viết này chúng ta sẽ xem một ví dụ làm thế nào để tạo một SortModel và sử dụng nó cho một Block để xắp xếp các ITEM(s) của Block này.
- Download FlutterArtist Demo
2. Country12aSortModelBuilder
In this example, CountryInfo is a data model representing information about a country. The model contains several properties that can be used for sorting.
CountryInfo
class CountryInfo {
String id;
String name;
String nameInEnglish;
String countryCode;
String isoCode2;
String isoCode3;
int population;
int area;
double? gdp;
}SortModelBuilder defines:
- Sorting criteria
- Comparison rules for client-side sorting
This builder is used by the Block to create SortModel instances for both client-side and server-side sorting.
Block (*)
SortModel<ITEM>? get clientSideSortModel;
SortModel<ITEM>? get serverSideSortModel;country12a_sort_model_builder.dart
class Country12aSortModelBuilder extends SortModelBuilder<CountryInfo> {
Country12aSortModelBuilder({
required super.clientSideSortMode,
required super.serverSideSortMode,
});
@override
SortModelStructure defineSortModelStructure() {
return SortModelStructure(
sortCriterionDefs: [
SortCriterionDef(
criterionName: 'nameInEnglish',
text: 'Name In English',
translationKey: "country.nameInEnglish",
),
SortCriterionDef(
criterionName: 'population',
text: 'Population',
translationKey: "country.population",
serverSideConfig: SortCriterionConfig(
initialSortDirection: SortDirection.desc,
),
),
SortCriterionDef(
criterionName: 'area',
text: 'Area',
translationKey: "country.area",
serverSideConfig: SortCriterionConfig(
initialSortDirection: SortDirection.asc,
),
),
],
);
}
@override
Comparable? getComparisonValue({
required CountryInfo item,
required String criterionName,
}) {
if (criterionName == "nameInEnglish") {
return item.nameInEnglish;
} else if (criterionName == "population") {
return item.population;
} else if (criterionName == "area") {
return item.area;
}
return null;
}
@override
String? getTranslationText({required String translationKey}) {
return null;
}
}3. Country12aShelf
After creating Country12aSortModelBuilder, you need to register it as a component of Country12aBlock inside the Shelf.
country12a_shelf.dart
class Country12aShelf extends Shelf {
@override
ShelfStructure defineShelfStructure() {
return ShelfStructure(
filterModels: {},
blocks: [
Country12aBlock(
name: Country12aBlock.blkName,
description: null,
config: BlockConfig(
pageable: Pageable(pageSize: 5),
clientSideSortStrategy: SortStrategy.modelBased,
),
filterModelName: null,
formModel: null,
childBlocks: [],
sortModelBuilder: Country12aSortModelBuilder(
clientSideSortMode: SortMode.single,
serverSideSortMode: SortMode.single,
),
),
],
);
}
Country12aBlock findCountry12aBlock() {
return findBlock(Country12aBlock.blkName) as Country12aBlock;
}
}No ADS
BlockConfig.clientSideSortStrategy
The BlockConfig.clientSideSortStrategy parameter defines how the Block handles client-side sorting.
BlockConfig(
...
clientSideSortStrategy: SortStrategy.modelBased,
),none | With this configuration, this Block will not support client-side sorting (including manual sorting) and block.clientSideSortModel will always return null. |
modelBased | With this configuration, Block will apply sorting on the client side if you provide it with a SortModelBuilder, then block.clientSideSortModel will be guaranteed to be non-null. |
manual | With this configuration, Block accepts manual arrangement of its ITEM(s) via drag and drop on the interface. In this case block.clientSideSortModel will always be null.
|
4. DropdownSortPanel
DropdownSortPanel is a UI widget that allows users to select sorting criteria and direction through a dropdown menu.

You can write your own SortPanel widgets by extending the SortPanel class or simply use widgets already created by FlutterArtist.

An example with BreadcrumbSortPanel:
Here are a few style(s) you can apply to DropdownSortPanel:
Modern Pill | Enterprise | Soft UI |
style12a.dart
final defaultStyle12a = DropdownSortPanelStyle();
final modernPillStyle12a = DropdownSortPanelStyle(
textStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: Colors.indigo,
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Colors.indigo.withAlpha(20),
borderRadius: BorderRadius.circular(25),
border: Border.all(color: Colors.indigo.withAlpha(50)),
),
dropdownIcon: Icons.unfold_more_rounded,
dropdownIconColor: Colors.indigo,
);
final enterpriseStyle12a = DropdownSortPanelStyle(
textStyle: const TextStyle(fontSize: 14, color: Colors.black87),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Colors.white,
border: Border(bottom: BorderSide(color: Colors.grey.shade400, width: 1.5)),
),
dropdownIcon: Icons.unfold_more_rounded,
dropdownIconColor: Colors.grey.shade700,
);
final softUIStyle12a = DropdownSortPanelStyle(
textStyle: const TextStyle(fontSize: 14, color: Colors.blueGrey),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(10),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
dropdownIcon: Icons.unfold_more_rounded,
);No ADS
How to use DropdownSortPanel:

if (country12aBlock.serverSideSortModel != null)
DropdownSortPanel.simple(
sortModel: country12aBlock.serverSideSortModel!,
),
if (country12aBlock.clientSideSortModel != null)
DropdownSortPanel.simple(
sortModel: country12aBlock.clientSideSortModel!,
),Future<void> _clearCriteria() async {
await serverSideSortModel.clearAllSorts();
}5. Country12aBlock
In case a Block uses SortModel for the server side, you need to pay attention to the sortableCriteria parameter of the Block.performQuery() method. SortableCriteria only includes criteria that have direction, or in other words, criteria that have a clear sorting direction, ascending or descending, assigned.
country12a_block.dart (*)
class Country12aBlock
extends
Block<
String, //
CountryInfo,
CountryData,
EmptyFilterInput,
EmptyFilterCriteria,
EmptyFormInput,
EmptyAdditionalFormRelatedData
> {
static const blkName = "country12a-block";
final countryRestProvider = CountryRestProvider();
@override
Future<ApiResult<PageData<CountryInfo>?>> performQuery({
required Object? parentBlockCurrentItem,
required EmptyFilterCriteria filterCriteria,
required SortableCriteria sortableCriteria,
required Pageable pageable,
}) async {
return await countryRestProvider.query(
sortableCriteria: sortableCriteria,
pageable: pageable,
);
}
...
}Convert the SortableCriteria object to a String before passing it to the server:
print(sortableCriteria.toSignedString());
// Output:
// +criterion1,-criterion2
print(sortableCriteria.toJsonString());
// Output:
// {"criterion1": "asc", "criterion2": "desc"}After converting SortableCriteria into a String, you can pass this value to the Query API. The string will be parsed on the server side to determine the sorting criteria.
country_rest_provider.dart (**)
...
Future<ApiResult<CountryInfoPage>> query({
required Pageable pageable,
SortableCriteria? sortableCriteria,
String? searchText,
}) async {
Map<String, dynamic>? queryParameters = {
"currentPage": pageable.page,
"pageSize": pageable.pageSize,
"searchText": searchText,
// Json String: '{"criterion1": "asc", "criterion2": "desc"}'.
"jsonSortableCriteria": sortableCriteria?.toJsonString(),
};
// /rest/countryInfoPage
ApiResult<CountryInfoPage> result = await flutterArtistDio.jsonGet(
"/rest/countryInfoPage",
queryParameters: queryParameters,
converter: CountryInfoPage.fromMap,
);
return result;
}No ADS
FlutterArtist
- Basic concepts in Flutter Artist
- FlutterArtist Block ex1
- FlutterArtist Filter Example
- FlutterArtist FilterModel MultiOptFilterCriterion ex1
- FlutterArtist FilterInput Example 1
- FlutterArtist Form ex1
- The idea of designing filter models in FlutterArtist
- FlutterArtist FormModel.patchFormFields() Ex1
- FlutterArtist BlockQuickItemUpdateAction Example
- FlutterArtist BlockNumberPagination Ex1
- FlutterArtist GridView Infinite Scroll Example
- FlutterArtist BlockQuickMultiItemCreationAction Example
- FlutterArtist ListView Infinite Scroll Pagination Example
- FlutterArtist Pagination
- FlutterArtist Sort DropdownSortPanel Example
- FlutterArtist Dio
- FlutterArtist BlockBackendAction Example
- FlutterArtist BackgroundWebDownloadAction Example
- FlutterArtist StorageBackendAction ex1
- FlutterArtist Block External Shelf Event ex1
- FlutterArtist Filter FormBuilderMultiDropDown Ex1
- FlutterArtist Master-detail Blocks ex1
- FlutterArtist Scalar ex1
- FlutterArtist Pagination Davi table Infinite Scroll Ex1
- FlutterArtist Filter Tree FormBuilderField ex1
- FlutterArtist Filter FormBuilderRadioGroup ex1
- FlutterArtist Form Parent-child MultiOptFormProp ex1
- FlutterArtist Manual Sorting ReorderableGridView Example
- FlutterArtist Manual Sorting ReorderableListView
- FlutterArtist Scalar External Shelf Event ex1
- FlutterArtist Code Flow Viewer
- FlutterArtist Log Viewer
- FlutterArtist config
- FlutterArtist StorageStructure
- FlutterArtist Debug Storage Viewer
- FlutterArtist DebugMenu
- FlutterArtist Debug UI Components Viewer
- FlutterArtist Debug Shelf Structure Viewer
- FlutterArtist Context Provider Views
- FlutterArtist FilterModelStructure ex1
- FlutterArtist FilterModelStructure ex2
- FlutterArtist FilterModelStructure ex3
- FlutterArtist Internal Shelf Event ex1
- FlutterArtist Deferring External Shelf Events (Ex1)
- FlutterArtist DropdownSortPanel
Show More
