1

Hi I am beginner in ROR and working on very simple project using view_components and stimulus js. I have InputCommentComponent view_component which I wanted to append as a child node in div by stimulus controller on click of Some button. But my component is undefined inside stimulus controller. How can I access it and append to div.

//input_comment_compopnent.html.erb
<%= form_with(model: @comment, local: true,  data: { turbo: false}) do |f| %>
  <div class="mb-4">
    <%= f.text_field :description, :required => true, class: "mb-3 w-2/3 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500", placeholder: "Add Comment ..." %>
    <%= f.hidden_field :post_id, value: @post_id %>
    <%= f.hidden_field :user_id, value: @user_id %>
    <%= f.hidden_field :reply_to, value: @reply_to %>
    <div class='sm:flex sm:flex-row-reverse mb-4 w-2/3'>
      <%= f.submit 'Submit', class: "inline-flex items-center justify-center px-4 py-2 bg-brand-primary font-semibold capitalize text-white hover:bg-brand-primary-hover active:bg-brand-primary disabled:opacity-25 transition" %>
    </div>
  </div>
<% end %>

// input_comment_component.rb
class Input::InputCommentComponent < ViewComponent::Base
  def initialize(comment: nil, post_id: nil, user_id: nil, reply_to: nil)
    @comment = comment
    @post_id = post_id
    @user_id = user_id
    @reply_to = reply_to
  end

end

//comment_controller.js
import {Controller} from '@hotwired/stimulus'

export default class extends Controller {
  static targets = ['wrapper']

  addComment() {
    this.wrapperTarget.appendChild(Input::InputCommentComponent.new)
    // or
    this.wrapperTarget.appendChild(render(Input::InputCommentComponent.new))

  }
}

But I can't access component inside controller and getting some syntax error as attached. enter image description here

Any help or hint would be Appreciated.

Afzal Ali
  • 880
  • 8
  • 25

2 Answers2

1

You cant render a view component component inside stimulus, because the component need to be rendered as server side and when you are working with stimulus you are working at client side. So you should use a turbo frame (https://turbo.hotwired.dev/) to render this component async.

  • First create a turbo frame end-points.
  • After that create a request to call this turbo end-point and append the html code
  • Thanks for your response but I don't want to install any other package. Is there any other workaround you can suggest? – Afzal Ali Aug 26 '22 at 04:45
  • Yes, you can do the same thing with .js.erb file, something like this (http://railscasts.com/episodes/136-jquery-ajax-revised?view=asciicast). Using j render to render your ViewComponent – Pedro Augusto Ramalho Duarte Aug 26 '22 at 16:34
0

A really elegant and easy way to append the view component to any Dom element without any JS is by using stimulus_reflex to broadcast your view component with cable_ready

stimulus reflex allows you to define a reflex class in ruby and call it on the Dom element ex:

example_reflex.rb

class ExampleReflex < StimulusReflex::Reflex

  def trigger
    cable_ready.append(
      selector: "#targeted-div", 
      html: render(Input::InputCommentComponent.new)).broadcast
    morph :nothing
  end
end

example_view.html.erb

<div id="targeted-div" ></div>
<button data-reflex="click->ExampleReflex#trigger" > click to append View component </button>
Omar Luq
  • 16
  • 4