|
1 | 1 | # Collection
|
2 | 2 |
|
| 3 | +With the collection component you can display active record model or similar collections and add 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. |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +## Usage |
| 8 | + |
| 9 | +In order to use a collection on your page or component you need to include matestack collection helper `Matestack::Ui::Core::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`. |
| 10 | + |
| 11 | +We recommend setting up your collection inside the `prepare` method of your page or component. |
| 12 | + |
| 13 | +```ruby |
| 14 | +class Shop::Pages::Products::Index < Matestack::Ui::Page |
| 15 | + include Matestack::Ui::Core::Collection::Helper |
| 16 | + |
| 17 | + def prepare |
| 18 | + @collection_id = 'products-collection' |
| 19 | + @collection = set_collection( |
| 20 | + id: @collection_id, |
| 21 | + data: Products.all |
| 22 | + ) |
| 23 | + end |
| 24 | + |
| 25 | + def response |
| 26 | + async id: 'product-collection', rerender_on: 'product-collection-udpate' do |
| 27 | + collection_content @collection.config do |
| 28 | + @collection.paginated_data.each do |product| |
| 29 | + paragraph text: product.name |
| 30 | + end |
| 31 | + end |
| 32 | + end |
| 33 | + end |
| 34 | + |
| 35 | +end |
| 36 | +``` |
| 37 | + |
| 38 | +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. |
| 39 | + |
| 40 | +### Pagination |
| 41 | + |
| 42 | +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. |
| 43 | + |
| 44 | +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. |
| 45 | + |
| 46 | +```ruby |
| 47 | +class Shop::Pages::Products::Index < Matestack::Ui::Page |
| 48 | + include Matestack::Ui::Core::Collection::Helper |
| 49 | + |
| 50 | + def prepare |
| 51 | + @collection_id = 'products-collection' |
| 52 | + base_query = Products.all |
| 53 | + @collection = set_collection( |
| 54 | + id: @collection_id, |
| 55 | + data: base_query, |
| 56 | + init_limit: 20, |
| 57 | + base_count: base_query.count |
| 58 | + ) |
| 59 | + end |
| 60 | + |
| 61 | + def response |
| 62 | + async id: 'product-collection', rerender_on: 'product-collection-udpate' do |
| 63 | + collection_content @collection.config do |
| 64 | + @collection.paginated_data.each do |product| |
| 65 | + paragraph text: product.name |
| 66 | + end |
| 67 | + end |
| 68 | + end |
| 69 | + pagination |
| 70 | + end |
| 71 | + |
| 72 | + def pagination |
| 73 | + plain "showing #{@my_collection.from}" |
| 74 | + plain "to #{@my_collection.to}" |
| 75 | + plain "of #{@my_collection.filtered_count}" |
| 76 | + plain "from total #{@my_collection.base_count}" |
| 77 | + collection_content_previous do |
| 78 | + button text: "previous" |
| 79 | + end |
| 80 | + @my_collection.pages.each do |page| |
| 81 | + collection_content_page_link page: page do |
| 82 | + button text: page |
| 83 | + end |
| 84 | + end |
| 85 | + collection_content_next do |
| 86 | + button text: "next" |
| 87 | + end |
| 88 | + end |
| 89 | + |
| 90 | +end |
| 91 | +``` |
| 92 | + |
| 93 | + |
| 94 | +### Filtering |
| 95 | + |
| 96 | +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. |
| 97 | + |
| 98 | +Let's filter our collection by name. |
| 99 | + |
| 100 | +```ruby |
| 101 | +class Shop::Pages::Products::Index < Matestack::Ui::Page |
| 102 | + include Matestack::Ui::Core::Collection::Helper |
| 103 | + |
| 104 | + def prepare |
| 105 | + @collection_id = 'products-collection' |
| 106 | + base_query = Products.all |
| 107 | + |
| 108 | + filter = get_collection_filter(@collection_id) |
| 109 | + filtered_query = Products.where('name LIKE ?', filter[:name]) |
| 110 | + |
| 111 | + @collection = set_collection( |
| 112 | + id: @collection_id, |
| 113 | + data: base_query, |
| 114 | + init_limit: 20, |
| 115 | + base_count: base_query.count, |
| 116 | + filtered_count: filtered_query.count |
| 117 | + ) |
| 118 | + end |
| 119 | + |
| 120 | + def response |
| 121 | + filter |
| 122 | + async id: 'product-collection', rerender_on: 'product-collection-udpate' do |
| 123 | + collection_content @collection.config do |
| 124 | + @collection.paginated_data.each do |product| |
| 125 | + paragraph text: product.name |
| 126 | + end |
| 127 | + end |
| 128 | + end |
| 129 | + pagination |
| 130 | + end |
| 131 | + |
| 132 | + def filter |
| 133 | + collection_filter @collection.config do |
| 134 | + collection_filter_input key: :name, type: :text |
| 135 | + collection_filter_submit do |
| 136 | + button text: 'Filter' |
| 137 | + end |
| 138 | + collection_filter_reset do |
| 139 | + button text: 'Reset' |
| 140 | + end |
| 141 | + end |
| 142 | + end |
| 143 | + |
| 144 | + #... |
| 145 | + |
| 146 | +end |
| 147 | +``` |
| 148 | + |
| 149 | +That's it. Now we can filter our collection by product name. |
| 150 | + |
| 151 | + |
| 152 | +### Ordering |
| 153 | + |
3 | 154 | 
|
0 commit comments