How to create a React modal within a Ruby on Rails view?

Hi all,

I’m working on a Ruby on Rails app and I’m getting trouble when I try to create a React component that opens within a RoR view.

Here is my view so far:

<%= link_to react_partner_search_advanced_admin_partners_path(project_id: project.id), data: { remote: true, "partner-search-modal": true } do %>
  <i class="fab fa-searchengin"></i>
<% end %>

My action in my controller:

def react_partner_search
  @project = Project.find(params[:project_id])
  render layout: false
end

My react_component view:

<%= react_component("PartnerSearchApp", props: { project_address: @project&.project_or_client_full_address }, prerender: false) %>

And my React component:

import React from 'react';
import Modal from 'react-modal';
import { defaultModalStyles } from '../features/utilities/modalStyles';

const PartnerSearchApp = (props) => {
  return (
    <Modal isOpen={true} style={defaultModalStyles} appElement={document.body}>
      <h1>{props.project_address}</h1>
    </Modal>
  )
}

export default PartnerSearchApp;

When I click on my link, I’m listening for an "ajax:success" event. When it is triggered, I retrieve the response from the server. It is an HTML response that contains the whole 3 points exposed on this page: https://www.shakacode.com/react-on-rails/docs/guides/client-vs-server-rendering/

And this is precisely here that I’m stuck: my component is empty and there is no modal or content within it: <div id="PartnerSearchApp-react-component-xxxxx"> How can I retrieve my whole component and add it to my RoR view?

Thank you so much for your help!

I finally ended with a solution!

In my partner_search_bundle.js, I did:

import ReactOnRails from 'react-on-rails';
import PartnerSearchApp from '../bundles/PartnerSearch/startup/PartnerSearchApp';

// This listener is used to open PartnerSearchModal component. We need
// to wait that turbolinks is loaded to look for the modal link element.
document.addEventListener("turbolinks:load", () => {
  const modalLink = document.querySelector('[data-partner-search-modal]');

  if (modalLink) {
    // If server returns a success ajax answer, we retrieve the HTML response that
    // contains 3 elements we must use to rehydrate our PartnerSearch component:
    // 1. a script within the head tag, 2. a script within the body tag, 3. a div
    // within the body tag. More infos here: https://bit.ly/3Dp4atH
    modalLink.addEventListener("ajax:success", (e) => {
      const response = e.detail[0];

      document.head.append(response.head.children[0]);
      // We can't iterate through our body response because the append()
      // function remove the element from the its former parent.
      document.body.append(response.body.children[0]);
      document.body.append(response.body.children[0]);

      // Now we have all the 3 elements on our current body, we can reload the
      // ReactOnRails script to recreate our component in the current view.
      ReactOnRails.reactOnRailsPageLoaded();
    });
  }
})

ReactOnRails.register({ PartnerSearchApp });

Can be probably improved, but it works so far!

1 Like