Select
Iridium provides a basic select component to allow your users to search through and select from a list of elements.
You can create a select option simply using
FormSelect("cities")Common Methods
For a list of common field component methods, see here.
Getting Started
Map Ordering
Unsorted Maps
Go does not provide a built-in data structure for maintaining insertion order into maps.
Iridium has it's own ordered_map collection to solve this issue. This means you're required to use or satisfy our ordered_map struct/interface and pair interface, to populate a list of dropdown items with a particular order. If you don't care about order, you can pass in a simple map[string]string as well.
Creating an ordered map
Singularly create your ordered map:
import "github.com/iridiumgo/iridium/core/collections"
myOrderedMap := collections.NewOrderedMap[string,string]()
myOrderedMap.Set("toronto", "Toronto")
// ... add more if desiredBulk insert ordered map:
import "github.com/iridiumgo/iridium/core/collections"
pairs := []collections.Pair[string,string]{
{Key: "toronto", Value: "The 6ix"},
{Key: "vancouver", Value: "Vancity"},
{Key: "montreal", Value: "Sin City"},
{Key: "calgary", Value: "Cowtown"},
}
myOrderedMap := collections.NewOrderedMapFromPairs(pairs)(Also supports spreading via NewOrderedMapFromVPairs)
Options
To set an ordered list of options, you can use the following methods:
// static
FormSelect("cities").
Options(myOrderedMap) // <- look up a section on how to create
// callback
FormSelect("cities").
OptionsFn(
func(ctx FieldContext) collections.IOrderedMap {
// This is alow a great spot to access your database
// or a model from the `ctx` variable to set your options!
om := collections.NewOrderedMap[string,string]()
om.Set("toronto", "Toronto")
return om
}
)Preloading Considerations
By default, when using any of the Options methods, all options are sent directly to the client and searched client side.
This is nice for reasonably sized options, but is not recommended for very large number of records. To preload a few items, and then allow users to search server side, see our SearchResultsUsing method.
Options Random
As discussed above, you are able to provide a basic map[string]string if the order of elements is no concern:
// static
FormSelect("cities").
OptionsRandom(map[string]string{"toronto", "Toronto"})
// callback
FormSelect("cities").
OptionsRandomFn(
func (ctx FieldContext) map[string]string {
return map[string]string{"toronto", "Toronto"}
}
)Multiple
You can allow users to select multiple options using the Multiple method as so:
// static
FormSelect("name").
Multiple()
// callback
FormSelect("name").
MultipleFn(
func (ctx FieldContext) bool {
return true
},
)Setting up Multiple
Keep in mind, your targeted struct field should be []string to properly deserialize your multiple options properly.
If you're using a GORM driver, keep in mind it does not natively support []string as a struct field.
Tips
- By default,
cmd+clickwill remove an option you click. You have the option to clear all options, or click an option'sXicon to deselect your row as well.
Searchable
Searchable allows you to search your dropdown by providing an input box in your popover:
// static
FormSelect("name").
Searchable()
// callback
FormSelect("name").
SearchableFn(
func (ctx FieldContext) bool {
return false
},
)Searchable Notes
- If you've enabled
SearchResultsUsing, your search box will perform a backend searching using HTMX. - If you've provided
Optionsinstead, your search box will perform a client side search using Alpine.Js
Scrollable
Scrollable enables your select options popover to be a scrollable area, rather than showing all your options on the screen. This is highly recommended if your options will be longer than a handful.
// static
FormSelect("name").
Scrollable()
// callback
FormSelect("name").
ScrollableFn(
func (ctx FieldContext) bool {
return true
},
)Nullable
Nullable will allow users to deselect options once they've been selected. This option is always true if multiple is enabled.
Users can deselect an option by click on their selection in the dropdown, or by clicking the X icon in the dropdown button
// static
FormSelect("name").
Nullable()
// callback
FormSelect("name").
NullableFn(
func (ctx FieldContext) bool {
return true
},
)PlaceHolder Message
You can provide a placeholder message to display in your dropdown if a user has not made any selections as so:
// static
FormSelect("name").
Placeholder("Please make your selection!")
// callback
FormSelect("name").
PlaceholderFn(
func (ctx FieldContext) string {
return "Please make your selection"
},
)No Results Message
You can provide a message to display if a no options are present in your select dropdown (either due to no options, or a search returning no options):
// static
FormSelect("name").
NoResults("Hey! No results were found. Sorry!")
// callback
FormSelect("name").
NoResultsFn(
func (ctx FieldContext) string {
return "Nothing here!"
},
)Search Results Using
OptionLabelFromValue is required when using this method.
The SearchResultsUsing method allows your user to search in your dropdown on the server side. This is excellent for a large number of records.
The callback you create will fire whenever a user searches in your dropdown box.
// with order
FormSelect("names").
Searchable().
SearchResultsUsing(
func (ctx SearchContext) collections.IOrderedMap[string,string]{
users := GetUsers(ctx.Search)
// Create an ordered map to guarantee option order
userPairs := make([]collections.Pair[string, string], len(users))
for _, user := range users {
userPairs = append(userPairs, collections.Pair[string,string]{
// We'll use their name as the key. The Value can changed to anything for display purposes.
// We're captializaing their names as an example.
Key: user.Name, Value: strings.ToUpper(user.Name),
})
}
return collections.NewOrderedMapFromPairs(userPairs)
}
)
// get users utility function.
// As an example, we're query our Users' gorm models.
// And filtering their names based on a ILIKE query + a user's search
func GetUsers(search string) []models.Users {
var users []models.User
// Query the first 20 users whose email contains the search term
if err := gormDBPtr.
Model(&models.User{}).
Where("name ILIKE ?", "%"+search+"%").
Limit(20).
Find(&users).Error; err != nil {
// Optionally log/handle the error and return empty options
return []models.Users{}
}
return users
}Search Results Using Random
OptionLabelFromValue is required when using this method
If you do not care about the ordering of elements, you can also use the random method variant. More..
// random order
FormSelect("names").
Searchable().
SearchResultsUsingRandom(
func (ctx FieldContext, search string) map[string]string {
var users []models.User
users := GetUsers(search)
// Build options map in random order (value -> label)
options := make(map[string]string, len(users))
for _, u := range users {
options[u.Name] = u.Name
}
return options
}
)Option Label From Value
OptionLabelFromValue is a method that is required for any SearchResultsUsing method and your DefaultValue method.
Iridium needs you to specify how to find the label for any option. This is not required when using an Options method as you already provide all the required labels.
// Here, please assume we're working on a form for a `User` model
// Therefore, while the key of your dropdown options is the `User` ID,
// Iridium still needs to be told how that value maps to a label
OptionLabelFromValue(func(ctx FieldContext, value string) (string, error) {
var user models.User
database.DB.Find(&user, value)
return user.Name, nil
}).In the example above, you can see we map a user's ID to a user's name. Therefore the options for your dropdown have a key of User Ids, and labels of User Names.
Remote Search Debounce
You can specify the search debounce when performing a remote search as so:
// static
FormSelect("name").
RemoteSearchDebounceMs(1000)
// callback
FormSelect("name").
RemoteSearchDebounceMsFn(
func (ctx FieldContext) uint {
return 235
}
)Native
By default, Iridium renders a custom, styled, dropdown as part of your views.
If you'd rather render your browser's native dropdown, you can do so as follows:
// static
FormSelect("cities").
Native()
// callback
FormSelect("cities").
NativeFn(
func (ctx FieldContext) bool {
return false
}
)