Open a popover from another one

This example requires the Stimulus controller setup shown in Use Stimulus and Turbo example.

Demo

<%# app/views/projects/index.html.erb %>

<table class="table">
  <thead>
    <th class="w-1/4">Name</th>
    <th class="w-1/4">Manager</th>
    <th class="w-1/4">Actions</th>
  </thead>
  <tbody>
    <% @projects.each do |project| %>
      <tr>
        <td>
          <%= link_to project.name, project_path(project) %>
        </td>
        <td>
          <%= link_to project.manager, manager_path(project.manager), class: "link" %>
        </td>
        <td>
          <%# 
            this 'inline-block' and 'block' combination is required for the comment
            popover to match the width and placement of the actions popover.
          %>
          <div class="inline-block">
              <%= coupdoeil_popover_tag ProjectPopover.with(project:).actions, 
                                        nil, # popover options
                                        class: "inline-block" do %>
                <button type="button" class="btn">actions</button>
              <% end %>
              <%# this coup-doeil has no content since it's triggered manually %>
              <%= coupdoeil_popover_tag ProjectPopover.with(project:).comment,
                                        nil, # popover options
                                        class: "block",
                                        id: dom_id(project, :comment_popover)
              %>
          </div>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>
# app/popovers/project_popover.rb

class ProjectPopover < ApplicationPopover
  before_action :set_project

  default_options_for :actions, animation: false
  default_options_for :comment, animation: "fade-in"
  
  default_options_for :actions, :comment,
                      placement: "bottom-end, top-end",
                      offset: "0.25rem",
                      trigger: :click
  
  def actions
  end
  
  def comment
  end
  
  private
  
  def set_project
    @project = params[:project]
  end
end

Note that comment popover must have trigger option set to click so it doesn’t close when mouse is hovering over any other element.

<%# app/popovers/project_popover/actions.html.erb  %>

<ul class="menu bg-base-200 rounded-box w-56">
  <li>
    <%= button_tag "Comment",
                   type: :button,
                   data: {
                     action: "click->popover#openOtherPopover", # see stimulus controller below
                     popover_target_param: dom_id(@project, :comment_popover)
                   }
    %>
  </li>
  <%= coupdoeil_popover_tag ProjectPopover.with(project: @project).export_actions do %>
    <%# … %>
  <% end %>
</ul>
<%# app/popovers/project_popover/comment.html.erb  %>

<div class="bg-white p-2 rounded border border-gray-300 shadow">
  <%= form_for @project,
               html: { data: { action: "turbo:submit-end->popover#closeOnSubmitSuccess" } } do |f| %>
    <%= f.textarea :comment, class: "border-gray-300 rounded text-sm p-1" %>
    <%= f.submit "comment", class: "block w-full btn btn-xs btn-success" %>
  <% end %>
</div>
// app/javascript/controllers/popover_controller.js

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="popover"
export default class extends Controller {
  // check "Use Stimulus and Turbo" example page for rest of controller
  
  openOtherPopover(event) {
    const { target: coupdoeilId } = event.params
    const coupdoeil = document.getElementById(coupdoeilId)
    
    // it's always nice to help yourself understand your mistakes
    if (!coupdoeil) {
      throw new Error("No element was found with this id.")
    } else if (coupdoeil.tagName !== "COUP-DOEIL") {
      throw new Error("Element was found but it is not a coup-doeil.")
    }
    
    this.close() // close current popover
    coupdoeil.openPopover()
  }

  closeOnSubmitSuccess(event) {
    if (event.detail.success) {
      this.close()
    } else {
      // handle error if needed
    }
  }
}

The rest of the Stimulus controller can be seen in Use Stimulus and Turbo example. The full file can also be found in the repository: app/javascript/controllers/popover_controller.js.