Last active
November 1, 2023 23:19
-
-
Save nickalbrecht/549917881c2f78547366001a77a0b391 to your computer and use it in GitHub Desktop.
Custom Comparer<SelectListItem> implementation for use in ASPNETCore to handle prioritizing certain SelectListGroup to the top of the SELECT element before being passed to a View. NULL groups are put last, but the SelectListItem, with a NULL value is made first as I assume it's the "Pick One" place holder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class PrioritizedGroupsSelectListItemComparer : Comparer<SelectListItem> | |
{ | |
private readonly List<string> prioritizedGroupNames; | |
public PrioritizedGroupsSelectListItemComparer(params string[] prioritizedGroupNames) | |
{ | |
this.prioritizedGroupNames = prioritizedGroupNames.ToList(); | |
} | |
public PrioritizedGroupsSelectListItemComparer(IEnumerable<string> prioritizedGroupNames) | |
{ | |
this.prioritizedGroupNames = prioritizedGroupNames.ToList(); | |
} | |
public override int Compare(SelectListItem item1, SelectListItem item2) | |
{ | |
var item1IsEmpty = string.IsNullOrEmpty(item1.Value); | |
var item2IsEmpty = string.IsNullOrEmpty(item2.Value); | |
if (item1IsEmpty && !item2IsEmpty) return -1; // Only item1 has empty value, it should come first | |
if (!item1IsEmpty && item2IsEmpty) return 1; // Only item2 has empty value, it should come first | |
// technically they should never both be empty, as it's asummed only one item in the list will have an empty value, since it should be the "Pick one" option | |
var index1 = prioritizedGroupNames.IndexOf(item1.Group?.Name); | |
var index2 = prioritizedGroupNames.IndexOf(item2.Group?.Name); | |
// *** Both are in priority groups | |
if (index1 != -1 && index2 != -1) { | |
var comparison = index1.CompareTo(index2); //Compare based on the order the groups appear in the priority groups | |
if (comparison == 0) // If both in the same group... | |
{ | |
return string.Compare(item1.Text, item2.Text, StringComparison.CurrentCultureIgnoreCase); //..Then compare items alphabetically | |
} | |
return comparison; // Otherwise use the result of comparing the order in the priority group | |
} | |
// *** Only one is in a priority group | |
if (index1 != -1) return -1; | |
if (index2 != -1) return 1; | |
// *** Neither are in priority groups | |
// Both groups are empty | |
if (item1.Group == null && item2.Group == null) { | |
return string.Compare(item1.Text, item2.Text, StringComparison.CurrentCultureIgnoreCase); | |
} | |
// At least one group is empty, bump empty groups down | |
// Otherwise they'd be at the top, just below prioritized groups | |
if (item1.Group == null) return 1; | |
if (item2.Group == null) return -1; | |
// Both are non-null, non-priority groups, order groups alphabetically | |
var unprioritizedGroupComparison = string.Compare(item1.Group.Name, item2.Group.Name, StringComparison.CurrentCultureIgnoreCase); | |
if(unprioritizedGroupComparison == 0) | |
return string.Compare(item1.Text, item2.Text, StringComparison.CurrentCultureIgnoreCase); | |
else | |
return unprioritizedGroupComparison; | |
} | |
} | |
public static class SuggestedSelectListItemExtensionMethods | |
{ | |
private const string suggested = "Suggested"; | |
/// <summary> | |
/// Performs an <see cref="Enumerable.OrderBy()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. "Suggested" group is bumped to the top | |
/// </summary> | |
public static IOrderedEnumerable<SelectListItem> OrderBySuggested<TEnumerableSelectListItems>(this TEnumerableSelectListItems items) where TEnumerableSelectListItems : IEnumerable<SelectListItem> | |
{ | |
return items.OrderByPrioritizedGroups(suggested); | |
} | |
/// <summary> | |
/// Performs an <see cref="Enumerable.OrderBy()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. Prioritized group names are bumped to the top | |
/// </summary> | |
public static IOrderedEnumerable<SelectListItem> OrderByPrioritizedGroups<TEnumerableSelectListItems>(this TEnumerableSelectListItems items, IEnumerable<string> prioritizedGroupNames) where TEnumerableSelectListItems : IEnumerable<SelectListItem> | |
{ | |
return items.OrderBy(x => x, new PrioritizedGroupsSelectListItemComparer(prioritizedGroupNames)); | |
} | |
/// <summary> | |
/// Performs an <see cref="Enumerable.OrderBy()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. Prioritized group names are bumped to the top | |
/// </summary> | |
public static IOrderedEnumerable<SelectListItem> OrderByPrioritizedGroups<TEnumerableSelectListItems>(this TEnumerableSelectListItems items, params string[] prioritizedGroupNames) where TEnumerableSelectListItems : IEnumerable<SelectListItem> | |
{ | |
return items.OrderBy(x => x, new PrioritizedGroupsSelectListItemComparer(prioritizedGroupNames)); | |
} | |
/// <summary> | |
/// Performs a <see cref="List{SelectListItem}.Sort()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. "Suggested" group is bumped to the top | |
/// </summary> | |
public static void SortBySuggested(this List<SelectListItem> items) | |
{ | |
items.SortByPrioritizedGroups(suggested); | |
} | |
/// <summary> | |
/// Performs a <see cref="List{SelectListItem}.Sort()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. Prioritized group names are bumped to the top | |
/// </summary> | |
public static void SortByPrioritizedGroups(this List<SelectListItem> items, IEnumerable<string> prioritizedGroupNames) | |
{ | |
items.Sort(new PrioritizedGroupsSelectListItemComparer(prioritizedGroupNames)); | |
} | |
/// <summary> | |
/// Performs a <see cref="List{SelectListItem}.Sort()"/> on <see cref="SelectListItem"/>s, using a custom <see cref="IComparer<>"/> to order by <see cref="SelectListGroup.Name"/>, then by <see cref="SelectListItem.Text"/>. Prioritized group names are bumped to the top | |
/// </summary> | |
public static void SortByPrioritizedGroups(this List<SelectListItem> items, params string[] prioritizedGroupNames) | |
{ | |
items.Sort(new PrioritizedGroupsSelectListItemComparer(prioritizedGroupNames)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated to have overloads accepting
params string
instead of having to always create enumerable parameters