Overview
The collection component helps you display Active Record model or similar collections and adding features like filtering, paginating and ordering with ease. Each of these features requires no page reload to take effect, because the collection component leverages a async component in combination with the event hub to only reload the effected content of the collection.
As you might experienced or know, displaying a collection of components can pretty fast lead to slow page loads, because of to big collections, therefore often requiring pagination. To work with bigger collections you often need a filter or search and an ordering to improve the user experience of your app. The collection component reduces the complexity of implementing all typical collection features by hand.
In order to use a collection on your page or component you need to include Matestack's collection helper Matestack::Ui::VueJs::Components::Collection::Helper in the corresponding page or component. The helper provides a few methods. set_collection takes a hash as an argument and is responsible for setting up the collection component. It requires an :id and :data.
We recommend setting up your collection inside the prepare method of your page or component.
1
class Shop::Pages::Products::Index < Matestack::Ui::Page
2
3
include Matestack::Ui::VueJs::Components::Collection::Helper
4
5
def prepare
6
@collection_id = 'products-collection'
7
@collection = set_collection(
8
id: @collection_id,
9
data: Products.all
10
)
11
end
12
13
def response
14
async id: 'product-collection', rerender_on: "#{@collection_id}-update" do
15
collection_content @collection.config do
16
@collection.data.each do |product|
17
paragraph product.name
18
end
19
end
20
end
21
end
22
23
end
Copied!
This is a basic collection component rendering all products. So far there is no benefit in using the collection component instead of just rendering all products, but moving on from this we can now easily implement a pagination, filtering and ordering. The async component wrapping the collection_content is important to enable reloading filtered, ordered or paginated collections later without page reloads. A collection filter, order or pagination emits a "collection_id-update" event.

Pagination

Limiting the amount of displayed collection items increases our load time for bigger collections drastically, but a user needs to be able to click through all of your items. We achieve this by using pagination.
Pagination can be achieved quite easily with matestacks collection. We need to add a :init_limit and :base_count to our arguments of the set_collection call and change the usage of @collection.data to @collection.paginated_data. In order to give the user the option to switch between pages we add a pagination which display links to the previous and next page as well as all pages by using matestack collection helpers collection_content_previous, collection_content_next, collection_content_page_link. It also displays a few information about the pagination.
1
class Shop::Pages::Products::Index < Matestack::Ui::Page
2
3
include Matestack::Ui::VueJs::Components::Collection::Helper
4
5
def prepare
6
@collection_id = 'products-collection'
7
base_query = Products.all
8
@collection = set_collection(
9
id: @collection_id,
10
data: base_query,
11
init_limit: 20,
12
base_count: base_query.count
13
)
14
end
15
16
def response
17
async id: 'product-collection', rerender_on: "#{@collection_id}-update" do
18
collection_content @collection.config do
19
# now we use paginated_data!
20
@collection.paginated_data.each do |product|
21
paragraph product.name
22
end
23
# pagination has to be placed within the collection_content!
24
pagination_partial
25
end
26
end
27
end
28
29
def pagination_partial
30
plain "showing #{collection.from}"
31
plain "to #{@collection.to}"
32
plain "of #{@collection.base_count}"
33
collection_content_previous do
34
button "previous"
35
end
36
@collection.pages.each do |page|
37
collection_content_page_link page: page do
38
button page
39
end
40
end
41
collection_content_next do
42
button "next"
43
end
44
end
45
46
end
Copied!

Filtering

Filtering a collection can be done by using the collection_filter helper along with the collection_filter_input, collection_filter_submit and collection_filter_reset helpers. The input values of your collection filter are accessible in the prepare statement by using get_collection_filter(id), which takes the collection id and returns a hash containing the input keys and values.
Let's filter our collection by name.
1
class Shop::Pages::Products::Index < Matestack::Ui::Page
2
3
include Matestack::Ui::VueJs::Components::Collection::Helper
4
5
def prepare
6
@collection_id = 'products-collection'
7
base_query = Products.all
8
filtered_query = base_query
9
10
filter = get_collection_filter(@collection_id)
11
filtered_query = Products.where('name LIKE ?', filter[:name]) if filter[:name].present?
12
13
@collection = set_collection(
14
id: @collection_id,
15
data: filtered_query,
16
init_limit: 20,
17
base_count: base_query.count,
18
filtered_count: filtered_query.count
19
)
20
end
21
22
def response
23
filter_partial
24
async id: 'product-collection', rerender_on: "#{@collection_id}-update" do
25
collection_content @collection.config do
26
# here we use paginated_data!
27
@collection.paginated_data.each do |product|
28
paragraph product.name
29
end
30
# pagination has to be placed within the collection_content!
31
pagination_partial
32
end
33
end
34
35
end
36
37
def filter_partial
38
collection_filter @collection.config do
39
form_input key: :name, type: :text
40
button 'Filter', type: :submit
41
collection_filter_reset do
42
button 'Reset'
43
end
44
end
45
end
46
47
def pagination_partial
48
plain "showing #{@collection.from}"
49
plain "to #{@collection.to}"
50
plain "of #{@collection.base_count}"
51
collection_content_previous do
52
button "previous"
53
end
54
@collection.pages.each do |page|
55
collection_content_page_link page: page do
56
button page
57
end
58
end
59
collection_content_next do
60
button "next"
61
end
62
end
63
64
end
Copied!
That's it. Now we can filter our collection by product name.

Ordering

Ordering a collection can be achieved by using the collection_order_toggle helper along with get_collection_order to receive the selected order.
1
class Shop::Pages::Products::Index < Matestack::Ui::Page
2
3
include Matestack::Ui::VueJs::Components::Collection::Helper
4
5
def prepare
6
@collection_id = 'products-collection'
7
base_query = Products.all
8
9
order = get_collection_order(@collection_id)
10
ordered_query = Products.all.order(current_order)
11
12
@collection = set_collection(
13
id: @collection_id,
14
data: ordered_query,
15
init_limit: 20,
16
base_count: base_query.count
17
)
18
end
19
20
def response
21
order_partial
22
async id: 'product-collection', rerender_on: "#{@collection_id}-update" do
23
collection_content @collection.config do
24
# here we use paginated_data!
25
@collection.paginated_data.each do |product|
26
paragraph product.name
27
end
28
# pagination has to be placed within the collection_content!
29
pagination_partial
30
end
31
end
32
end
33
34
def order_partial
35
collection_order @my_collection.config do
36
plain "sort by:"
37
collection_order_toggle key: :title do
38
button do
39
plain "Title"
40
collection_order_toggle_indicator key: :title, asc: '&#8593;', desc: '&#8595;'
41
end
42
end
43
end
44
end
45
46
#...
47
48
end
Copied!

Using actions in collections

1
class Shop::Pages::Products::Index < Matestack::Ui::Page
2
3
include Matestack::Ui::VueJs::Components::Collection::Helper
4
5
def prepare
6
@collection_id = 'products-collection'
7
base_query = Products.all
8
@collection = set_collection(
9
id: @collection_id,
10
data: base_query,
11
init_limit: 20,
12
base_count: base_query.count
13
)
14
end
15
16
def response
17
async id: 'product-collection', rerender_on: "#{@collection_id}-update" do
18
collection_content @collection.config do
19
@collection.paginated_data.each do |product|
20
paragraph product.name
21
action my_action_config(product.id) do
22
button 'delete'
23
end
24
end
25
# pagination has to be placed within the collection_content!
26
pagination_partial
27
end
28
end
29
end
30
31
def my_action_config id
32
{
33
method: :delete,
34
path: my_delete_path(id: id),
35
success: {
36
emit: "#{@collection_id}-update" # has to match the rerender_on event schema!
37
}
38
}
39
end
40
41
# ...
42
43
end
Copied!
Last modified 7mo ago