Collection

Feel free to check out the component specs.

The collection component is designed to

  • 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: &#8593;)"
          # and and an "arrow down (unicode: &#8595;)" to
          # visualize the current order state
          collection_order_toggle_indicator key: :title, asc: '&#8593;', desc: '&#8595;'
          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

Last updated