komposable / komponent

An opinionated way of organizing front-end code in Ruby on Rails, based on components

Home Page:http://komponent.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rendering partial into component

florentferry opened this issue · comments

Problem

We need the ability to render partial inside a component. If that partial is inside the component, we need a way to prevent to give full path.

Example:

  components/
    button/
       _button.html.slim
       _icon.html.slim
/ frontend/components/button/_button.html.slim

= render("components/button/icon")

Solution 1


Add components folder and all subfolders to lookup. But the drawback is the addition of a lot of directories to lookup.

ActionController::Base.prepend_vew_path Dir["#{app.config.root}/frontend/**/*"]
/ frontend/components/button/_button.html.slim

= render("button/icon")

Solution 2


Add a render_partial helper to render partial inside component. We inject current component path to lookup in order to render the component, and restore default behavior after rendering.

def render_partial(partial_name, locals = {}, &block)
  benchmark("Rendered partial #{partial_name}") do
    context = controller.view_context
    view_paths = context.lookup_context.view_paths.dup
    components_path = Rails.root.join "frontend/components"

    capture_block = proc { capture(&block) } if block

    current_dir = Pathname.new(@virtual_path).dirname

    context.lookup_context.prefixes.prepend current_dir
    context.lookup_context.view_paths.unshift components_path

    partial_rendered = capture do 
      context.render partial_name, locals, &capture_block
    end

    context.lookup_context.prefixes.delete current_dir
    context.lookup_context.view_paths = view_paths

    partial_rendered
  end
end
/ frontend/components/button/_button.html.slim

= render_partial("icon")

Solution 3


Allow to have nested components inside component.

  components/
    button/
      _button
      ...
      title/
        _title
        ...

I like solution 2. It's not something that would happen in all components, so I think this approach is specific enough and does not seem to have impact on the rest of the features / architecture.