Skip to content

Commit

Permalink
Optionally preload async comboboxes (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefarias authored Nov 20, 2024
1 parent 23df4bc commit 6eca7a2
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 35 deletions.
7 changes: 4 additions & 3 deletions app/presenters/hotwire_combobox/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ def initialize(
name_when_new: nil,
open: false,
options: [],
preload: false,
request: nil,
value: nil, **rest)
@view, @autocomplete, @id, @name, @value, @form, @async_src, @label, @free_text, @request,
@name_when_new, @open, @data, @mobile_at, @multiselect_chip_src, @options, @dialog_label =
@preload, @name_when_new, @open, @data, @mobile_at, @multiselect_chip_src, @options, @dialog_label =
view, autocomplete, id, name.to_s, value, form, async_src, label, free_text, request,
name_when_new, open, data, mobile_at, multiselect_chip_src, options, dialog_label
preload, name_when_new, open, data, mobile_at, multiselect_chip_src, options, dialog_label

@combobox_attrs = input.reverse_merge(rest).deep_symbolize_keys
@association_name = association_name || infer_association_name
Expand All @@ -46,7 +47,7 @@ def render_in(view_context, &block)

private
attr_reader :view, :autocomplete, :id, :name, :value, :form, :free_text, :open, :request,
:data, :combobox_attrs, :mobile_at, :association_name, :multiselect_chip_src
:data, :combobox_attrs, :mobile_at, :association_name, :multiselect_chip_src, :preload

def canonical_id
@canonical_id ||= id || form&.field_id(name) || SecureRandom.uuid
Expand Down
11 changes: 10 additions & 1 deletion app/presenters/hotwire_combobox/component/paginated.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ def paginated?
end

def pagination_attrs
{ for_id: canonical_id, src: async_src }
{ for_id: canonical_id, src: async_src, loading: preload_next_page? ? :eager : :lazy }
end

private
def preload_next_page?
view.hw_first_page? && preload?
end

def preload?
preload.present?
end
end
4 changes: 2 additions & 2 deletions app/views/hotwire_combobox/_pagination.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%# locals: (for_id:, src:) -%>
<%# locals: (for_id:, src:, loading: :lazy) -%>

<%= tag.li id: hw_pagination_frame_wrapper_id(for_id), class: "hw_combobox__pagination__wrapper",
data: { hw_combobox_target: "endOfOptionsStream", input_type: params[:input_type], callback_id: params[:callback_id] },
aria: { hidden: true } do %>
<%= turbo_frame_tag hw_pagination_frame_id(for_id), src: src, loading: :lazy %>
<%= turbo_frame_tag hw_pagination_frame_id(for_id), src: src, loading: loading %>
<% end %>
8 changes: 6 additions & 2 deletions lib/hotwire_combobox/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def hw_combobox_options(options, render_in: {}, include_blank: nil, display: :to
end

def hw_paginated_combobox_options(options, for_id: params[:for_id], src: hw_fullpath_for_pagination, next_page: nil, render_in: {}, include_blank: {}, **custom_methods)
include_blank = params[:page].to_i > 0 ? nil : include_blank
include_blank = hw_first_page? ? include_blank : nil
options = hw_combobox_options options, render_in: render_in, include_blank: include_blank, **custom_methods
this_page = render "hotwire_combobox/paginated_options", for_id: for_id, options: options
next_page = render "hotwire_combobox/next_page", for_id: for_id, src: hw_combobox_next_page_uri(src, next_page, for_id)
Expand Down Expand Up @@ -106,7 +106,11 @@ def hw_pagination_frame_id(id)
end

def hw_combobox_page_stream_action
params[:page].to_i > 0 ? :append : :update
hw_first_page? ? :update : :append
end

def hw_first_page?
params[:page].to_i.zero?
end

def hw_uri_with_params(url_or_path, **params)
Expand Down
3 changes: 3 additions & 0 deletions test/dummy/app/controllers/comboboxes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def list_autocomplete
def async
end

def async_preload
end

def freetext_async
end

Expand Down
1 change: 1 addition & 0 deletions test/dummy/app/views/comboboxes/async_preload.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= combobox_tag "movie", movies_path, id: "movie-field", label: "Choose your movie!", preload: true %>
55 changes: 28 additions & 27 deletions test/dummy/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
Rails.application.routes.draw do
get "plain", to: "comboboxes#plain"
get "padded", to: "comboboxes#padded"
get "open", to: "comboboxes#open"
get "html_options", to: "comboboxes#html_options"
get "prefilled", to: "comboboxes#prefilled"
get "prefilled_html", to: "comboboxes#prefilled_html"
get "required", to: "comboboxes#required"
get "formbuilder", to: "comboboxes#formbuilder"
get "new_options", to: "comboboxes#new_options"
get "inline_autocomplete", to: "comboboxes#inline_autocomplete"
get "list_autocomplete", to: "comboboxes#list_autocomplete"
get "async", to: "comboboxes#async"
get "freetext_async", to: "comboboxes#freetext_async"
get "prefilled_async", to: "comboboxes#prefilled_async"
get "prefilled_form", to: "comboboxes#prefilled_form"
get "prefilled_free_text", to: "comboboxes#prefilled_free_text"
get "async_html", to: "comboboxes#async_html"
get "render_in", to: "comboboxes#render_in"
get "async_preload", to: "comboboxes#async_preload"
get "conflicting_order", to: "comboboxes#conflicting_order"
get "custom_attrs", to: "comboboxes#custom_attrs"
get "custom_events", to: "comboboxes#custom_events"
get "dialog", to: "comboboxes#dialog"
get "enum", to: "comboboxes#enum"
get "external_clear", to: "comboboxes#external_clear"
get "form_object", to: "comboboxes#form_object"
get "formbuilder", to: "comboboxes#formbuilder"
get "freetext_async", to: "comboboxes#freetext_async"
get "grouped_options", to: "comboboxes#grouped_options"
get "html_options", to: "comboboxes#html_options"
get "include_blank", to: "comboboxes#include_blank"
get "custom_events", to: "comboboxes#custom_events"
get "custom_attrs", to: "comboboxes#custom_attrs"
get "conflicting_order", to: "comboboxes#conflicting_order"
get "render_in_locals", to: "comboboxes#render_in_locals"
get "inline_autocomplete", to: "comboboxes#inline_autocomplete"
get "list_autocomplete", to: "comboboxes#list_autocomplete"
get "morph", to: "comboboxes#morph"
get "multiselect", to: "comboboxes#multiselect"
get "multiselect_dismissing", to: "comboboxes#multiselect_dismissing"
get "multiselect_async_html", to: "comboboxes#multiselect_async_html"
get "multiselect_prefilled_form", to: "comboboxes#multiselect_prefilled_form"
get "multiselect_custom_events", to: "comboboxes#multiselect_custom_events"
get "multiselect_dismissing", to: "comboboxes#multiselect_dismissing"
get "multiselect_new_values", to: "comboboxes#multiselect_new_values"
get "grouped_options", to: "comboboxes#grouped_options"
get "morph", to: "comboboxes#morph"
get "form_object", to: "comboboxes#form_object"
get "external_clear", to: "comboboxes#external_clear"
get "dialog", to: "comboboxes#dialog"
get "multiselect_prefilled_form", to: "comboboxes#multiselect_prefilled_form"
get "new_options", to: "comboboxes#new_options"
get "open", to: "comboboxes#open"
get "padded", to: "comboboxes#padded"
get "plain", to: "comboboxes#plain"
get "prefilled", to: "comboboxes#prefilled"
get "prefilled_async", to: "comboboxes#prefilled_async"
get "prefilled_form", to: "comboboxes#prefilled_form"
get "prefilled_free_text", to: "comboboxes#prefilled_free_text"
get "prefilled_html", to: "comboboxes#prefilled_html"
get "render_in", to: "comboboxes#render_in"
get "render_in_locals", to: "comboboxes#render_in_locals"
get "required", to: "comboboxes#required"

resources :movies, only: %i[ index update ]
get "movies_html", to: "movies#index_html"
Expand Down
5 changes: 5 additions & 0 deletions test/system/async_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,9 @@ class AsyncTest < ApplicationSystemTestCase
click_on_option "A Few Good Men"
assert_combobox_display_and_value "#movie-field", "A Few Good Men", movies(:a_few_good_men).id
end

test "preload" do
visit async_preload_path
assert_options_with count: 5, visible: :hidden
end
end

0 comments on commit 6eca7a2

Please sign in to comment.