display instances from a model (Active Record or similar)
filter the displayed instances without full page reload
paginate the displayed instances without full page reload
order the displayed instances without full page reload
The collection component should be as flexible as possible while still reducing the complexity of implementing all typical collection features by hand.
Prerequisites
We use an ActiveRecord Model in the following examples. This Model has two columns: id and title.
Examples
Filterable collection
In this example, we want to display ALL instances of DummyModel and filter the collection by title using a text input.
class Pages::MyApp::Collection < Matestack::Ui::Page
include Matestack::Ui::Core::Collection::Helper
def prepare
my_collection_id = "my-first-collection"
current_filter = get_collection_filter(my_collection_id)
my_base_query = DummyModel.all
my_filtered_query = my_base_query
.where("title LIKE ?", "%#{current_filter[:title]}%")
@my_collection = set_collection({
id: my_collection_id,
data: my_filtered_query
})
end
def response
heading size: 2, text: "My Collection"
filter
# the content has to be wrapped in an `async` component
# the event has to be "your_custom_collection_id" + "-update"
async rerender_on: "my-first-collection-update", id: "my-collection-content" do
content
end
end
def filter
collection_filter @my_collection.config do
collection_filter_input key: :title, type: :text, placeholder: "Filter by Title"
collection_filter_submit do
button text: "filter"
end
collection_filter_reset do
button text: "reset"
end
end
end
def content
collection_content @my_collection.config do
ul do
@my_collection.data.each do |dummy|
li do
plain dummy.title
end
end
end
end
end
end
Filtered & paginated collection
In this example, we want to display only a limited (10) amount of instances of DummyModel at once and filter the collection by title using a text input. We want to display the classic pagination buttons and information below the list of paginated instances.
class Pages::MyApp::Collection < Matestack::Ui::Page
include Matestack::Ui::Core::Collection::Helper
def prepare
my_collection_id = "my-first-collection"
current_filter = get_collection_filter(my_collection_id)
my_base_query = DummyModel.all
my_filtered_query = my_base_query
.where("title LIKE ?", "%#{current_filter[:title]}%")
@my_collection = set_collection({
id: my_collection_id,
data: my_filtered_query,
init_limit: 10, #set a limit
filtered_count: my_filtered_query.count, #tell the component how to count the filtered result
base_count: my_base_query.count #tell the component how to count the total amount
})
end
def response
heading size: 2, text: "My Collection"
filter
async rerender_on: "my-first-collection-update", id: "my-collection-content" do
content
end
end
def filter
collection_filter @my_collection.config do
collection_filter_input key: :title, type: :text, placeholder: "Filter by Title"
collection_filter_submit do
button text: "filter"
end
collection_filter_reset do
button text: "reset"
end
end
end
def content
collection_content @my_collection.config do
ul do
# now we use paginated_data!
@my_collection.paginated_data.each do |dummy|
li do
plain dummy.title
end
end
end
paginator #has to be placed within the `collection_content` component!
end
end
def paginator
plain "showing #{@my_collection.from}"
plain "to #{@my_collection.to}"
plain "of #{@my_collection.filtered_count}"
plain "from total #{@my_collection.base_count}"
collection_content_previous do
button text: "previous"
end
@my_collection.pages.each do |page|
collection_content_page_link page: page do
button text: page
end
end
collection_content_next do
button text: "next"
end
end
end
Filtered & paginated & ordered collection
In this example, we want to display only a limited (10) amount of instances of DummyModel at once and filter the collection by title using a text input. We want to display the classic pagination buttons and information below the list of paginated instances. Additionally, we want to order the collection by title ascending or descending.
class Pages::MyApp::Collection < Matestack::Ui::Page
include Matestack::Ui::Core::Collection::Helper
def prepare
my_collection_id = "my-first-collection"
current_filter = get_collection_filter(my_collection_id)
current_order = get_collection_order(my_collection_id) #now we need the current order state from the url params
my_base_query = DummyModel.all
my_filtered_query = my_base_query
.where("title LIKE ?", "%#{current_filter[:title]}%")
.order(current_order) # and apply the state to the query
@my_collection = set_collection({
id: my_collection_id,
data: my_filtered_query,
init_limit: 10,
filtered_count: my_filtered_query.count,
base_count: my_base_query.count
})
end
def response
heading size: 2, text: "My Collection"
filter
ordering
async rerender_on: "my-first-collection-update", id: "my-collection-content" do
content
end
end
def filter
collection_filter @my_collection.config do
collection_filter_input key: :title, type: :text, placeholder: "Filter by Title"
collection_filter_submit do
button text: "filter"
end
collection_filter_reset do
button text: "reset"
end
end
end
def ordering
collection_order @my_collection.config do
plain "sort by:"
collection_order_toggle key: :title do
button do
# we use an "arrow up (unicode: ↑)"
# and and an "arrow down (unicode: ↓)" to
# visualize the current order state
collection_order_toggle_indicator key: :title, asc: '↑', desc: '↓'
plain "title"
end
end
end
end
def content
collection_content @my_collection.config do
ul do
@my_collection.paginated_data.each do |dummy|
li do
plain dummy.title
end
end
end
paginator #has to be placed within the `collection_content` component!
end
end
def paginator
plain "showing #{@my_collection.from}"
plain "to #{@my_collection.to}"
plain "of #{@my_collection.filtered_count}"
plain "from total #{@my_collection.base_count}"
collection_content_previous do
button text: "previous"
end
@my_collection.pages.each do |page|
collection_content_page_link page: page do
button text: page
end
end
collection_content_next do
button text: "next"
end
end
end
Action enriched collection
In this example, we want to display ALL instances of DummyModel and filter the collection by title using a text input. Additionally we want to be able to delete an item of the list using the action component.
class Pages::MyApp::Collection < Matestack::Ui::Page
include Matestack::Ui::Core::Collection::Helper
def prepare
my_collection_id = "my-first-collection"
current_filter = get_collection_filter(my_collection_id)
my_base_query = DummyModel.all
my_filtered_query = my_base_query
.where("title LIKE ?", "%#{current_filter[:title]}%")
@my_collection = set_collection({
id: my_collection_id,
data: my_filtered_query
})
end
def response
heading size: 2, text: "My Collection"
filter
async rerender_on: "my-first-collection-update", id: "my-collection-content" do
content
end
end
def filter
collection_filter @my_collection.config do
collection_filter_input key: :title, type: :text, placeholder: "Filter by Title"
collection_filter_submit do
button text: "filter"
end
collection_filter_reset do
button text: "reset"
end
end
end
def content
collection_content @my_collection.config do
ul do
@my_collection.data.each do |dummy|
li do
plain dummy.title
action my_action_config(dummy.id) do
button text: "delete"
end
end
end
end
end
end
def my_action_config id
{
method: :delete,
path: :my_delete_path,
params:{
id: id
},
success: {
emit: "my-first-collection-update"
}
}
end
end