LiveTable.Select (live_table v0.2.0)
View SourceA module for handling select-based filters in LiveTable.
This module provides functionality for creating and managing select filters that can handle single or multiple selections. It supports both static options and dynamic option loading, with customizable appearances and templates.
Options
The module accepts the following options:
:label
- The label text for the select filter:options
- Static list of options for the select:options_source
- Function or module for dynamic option loading:option_template
- Custom template for rendering options:selected
- List of pre-selected values:loading_text
- Text to display while loading options:prompt
- Prompt text for the select:placeholder
- Placeholder text for the select:css_classes
- CSS classes for the main container:label_classes
- CSS classes for the label element:select_classes
- CSS classes for the select element
For default values, see: LiveTable.Select source code
Working with Options
There are two ways to configure and display options in the select filter:
1. Static Options
The simplest approach using a predefined list of options:
Select.new(:status, "status_select", %{
label: "Status",
options: [
%{label: "Active", value: [1, "Currently active"]},
%{label: "Pending", value: [2, "Awaiting processing"]},
%{label: "Archived", value: [3, "No longer active"]}
]
})
2. Dynamic Options via options_source
Load options dynamically using a function or module. Used for fetching new options based on typed input.
Uses apply/3
under the hood to apply the function. Uses live-select-change
event to update the options.
# Point to your custom function
Select.new({:suppliers, :name}, "supplier_name", %{
label: "Supplier",
options_source: {Demo.Catalog, :search_suppliers, []} # Same as you'd use for `apply/3`
})
# in your context module
def search_suppliers(text) do
Supplier
|> where([c], ilike(c.name, ^"%#{text}%"))
|> select([c], {c.name, [c.id, c.contact_info]})
|> Repo.all()
end
You could write your function to have other args passed to it as well. Just make sure the first arg is the text. It must return a tuple, with the first element being the label and the second being the value(or a list of fields).
Option Templates
You can provide custom templates for rendering options in two ways:
- Using the default template format for options with label and value pairs
- Providing a custom template function through the
:option_template
option
Default Template
The default template expects options in the format:
%{label: label, value: [id, description]}
The default template can be seen at git link
Custom Template
Custom templates can be provided as functions that take an option map and return rendered HTML:
def custom_template(option) do
assigns = %{option: option}
~H"""
<div class="flex flex-col">
<span class="font-bold"><%= @option.label %></span> inas
<span class="text-sm text-gray-500"><%= @option.value |> Enum.at(0) %></span>
</div>
"""
end
# in your filter definition
Select.new({:suppliers, :name}, "supplier_name", %{
label: "Supplier",
placeholder: "Search for suppliers...",
options_source: {Demo.Catalog, :search_suppliers, []}
option_template: &custom_template/1
})
Each method can be combined with others - for example, you could use dynamic or static options with custom templates.
Examples
If the field you want to use is part of the base schema(given to LiveResource
), you can simply pass the field name as an atom.
# Creating a basic select filter
Select.new(:category, "category_select", %{
label: "Category",
options: [
%{label: "Electronics", value: [1, "Electronics"]},
%{label: "Books", value: [2, "Books"]}
]
})
If its part of a joined schema, you can pass it as a tuple, with the table name and field name as shown-
# Creating a select filter with options loaded from database
Select.new({:suppliers, :name}, "supplier_name", %{
label: "Supplier",
options_source: {Demo.Catalog, :search_suppliers, []}
})
# Advanced example with all options
Select.new({:category, :name}, "category_name", %{
label: "Category",
placeholder: "Search for categories...",
options_source: {Demo.Catalog, :search_categories, [optional args]}
option_template: &custom_template/1,
})
Currently, nested relations are not supported.
TODO:
- [ ] Interface the select classes with the live-select component.
- [ ] Update state from URL params.
- [ ] Add support for multiple option selection.
- [ ] Move away from live_select