Class: ViewComponentReflex::Component
- Inherits:
-
ViewComponent::Base
- Object
- ViewComponent::Base
- ViewComponentReflex::Component
- Defined in:
- app/components/view_component_reflex/component.rb
Class Method Summary collapse
Instance Method Summary collapse
- #collection_key ⇒ Object
- #component_controller(opts = {}, &blk) ⇒ Object
-
#key ⇒ Object
key is required if you’re using state We can’t initialize the session state in the initial method because it doesn’t have a view_context yet This is the next best place to do it.
- #stimulus_reflex? ⇒ Boolean
Class Method Details
.init_stimulus_reflex ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'app/components/view_component_reflex/component.rb', line 4 def init_stimulus_reflex klass = self @stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(StimulusReflex::Reflex) { def refresh!(primary_selector = "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]", *selectors) save_state @channel.send :render_page_and_broadcast_morph, self, [primary_selector, *selectors], { "dataset" => element.dataset.to_h, "args" => [], "attrs" => element.attributes.to_h, "selectors" => ["body"], "target" => "#{self.class.name}##{method_name}", "url" => request.url, "permanent_attribute_name" => "data-reflex-permanent" } end def refresh_all! refresh!("body") end # SR's delegate_call_to_reflex in channel.rb # uses method to gather the method parameters, but since we're abusing # method_missing here, that'll always fail def method(name) name.to_sym.to_proc end def respond_to_missing?(name, _ = false) !!name.to_proc end before_reflex do |a| a.send a.method_name throw :abort end def method_missing(name, *args) super unless respond_to_missing?(name) state.each do |k, v| component.instance_variable_set(k, v) end name.to_proc.call(component, *args) refresh! end define_method :component_class do @component_class ||= klass end private :component_class private def stimulus_controller component_class.stimulus_controller end def component return @component if @component @component = component_class.allocate reflex = self exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller] exposed_methods.each do |meth| @component.define_singleton_method(meth) do |*a| reflex.send(meth, *a) end end @component end def set_state(new_state = {}) ViewComponentReflex::Engine.state_adapter.set_state(self, element.dataset[:key], new_state) end def state ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key]) end def save_state new_state = {} component.instance_variables.each do |k| new_state[k] = component.instance_variable_get(k) end set_state(new_state) end }) end |
.stimulus_controller ⇒ Object
93 94 95 |
# File 'app/components/view_component_reflex/component.rb', line 93 def self.stimulus_controller name.chomp("Component").underscore.dasherize end |
Instance Method Details
#collection_key ⇒ Object
111 112 113 |
# File 'app/components/view_component_reflex/component.rb', line 111 def collection_key nil end |
#component_controller(opts = {}, &blk) ⇒ Object
101 102 103 104 105 106 107 108 109 |
# File 'app/components/view_component_reflex/component.rb', line 101 def component_controller(opts = {}, &blk) self.class.init_stimulus_reflex opts[:data] = { controller: self.class.stimulus_controller, key: key, **(opts[:data] || {}) } content_tag :div, capture(&blk), opts end |
#key ⇒ Object
key is required if you’re using state We can’t initialize the session state in the initial method because it doesn’t have a view_context yet This is the next best place to do it
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'app/components/view_component_reflex/component.rb', line 119 def key # we want the erb file that renders the component. `caller` gives the file name, # and line number, which should be unique. We hash it to make it a nice number key = caller.select { |p| p.include? ".html.erb" }[1]&.hash.to_s key += collection_key.to_s if collection_key if @key.nil? || @key.empty? @key = key end # initialize session state if !stimulus_reflex? || session[@key].nil? new_state = {} # this will almost certainly break blacklist = [ :@view_context, :@lookup_context, :@view_renderer, :@view_flow, :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key, :@helpers, :@controller, :@request ] instance_variables.reject { |k| blacklist.include?(k) }.each do |k| new_state[k] = instance_variable_get(k) end ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state) else ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v| instance_variable_set(k, v) end end @key end |
#stimulus_reflex? ⇒ Boolean
97 98 99 |
# File 'app/components/view_component_reflex/component.rb', line 97 def stimulus_reflex? helpers.controller.instance_variable_get(:@stimulus_reflex) end |