Stimulus js 跨控制器事件上下文

stu*_*eba 4 stimulusjs ruby-on-rails-7

我有两个独立的刺激控制器。一个用于管理表,另一个用于触发表的新行。

我在页面上有一个按钮,调用turbo-table-new-row#show函数,它确实调度事件并调用turbo-table#show函数,但我似乎无法访问turbo-表的“this”,所以我无法访问目标、值等......

如果我将按钮移动到涡轮表的范围内,我不需要第二个控制器,一切都会正常工作。但是,从 UI 角度来看,这是行不通的。

收到事件后如何访问接收控制器的“this”?

 <div data-controller="turbo-table-new-row turbo-table"
      data-action="turbo-table-new-row:show->turbo-table#display">

    <button data-action="click->turbo-table-new-row#show">
 </div> 
Run Code Online (Sandbox Code Playgroud)
 // turbo-table-new-row-controller

  show(e) {
   this.dispatch("show", { detail: { url: e.params.url} })
  }
Run Code Online (Sandbox Code Playgroud)
  // turbo-table-controller
show(e) {
        console.log("[turbo_table] - turbo-table-new-row->show event")
        console.log(e.detail.url)

  // I don't have access to the turbo-table-contoller 'this'

  this.hasPanelTarget ...

}
Run Code Online (Sandbox Code Playgroud)

LB *_*ton 6

当不在同一个 DOM 元素中时,应该可以从一个控制器分派事件并在另一个控制器中读取该事件。

当您从 JavaScript 分派事件时,它将在 DOM 树中冒泡到window. 您可以使用操作描述符监听全局事件,@window以捕获在控制器的 DOM 树外部冒泡的任何事件。

您可能需要小心检查它是否是您想要的“正确”事件,但作为基本设置,您需要添加@window数据操作。

例子

这是一个工作端到端示例,不是涡轮链接,其中表控制器不是添加行按钮的父级(它是同级)。使用窗口事件监听器方法,我们可以监听 DOM 树外部的事件。

this一旦表控制器接收到事件,类方法就应该可以毫无问题地访问该控制器。

如果您想访问原始触发按钮的目标元素,您可以通过event.target.

<main>
  <table data-controller="table" data-action="table-action:add@window->table#show">
    <thead>
      <tr>
        <th data-table-target="status"></th>
      </tr>
    </thead>
    <tr data-table-target="row">
      <td>Item 1</td>
    </tr>
    <tr data-table-target="row">
      <td>Item 2</td>
    </tr>
    <tr data-table-target="row">
      <td>Item 3</td>
    </tr>
    <tr data-table-target="row">
      <td>Item 4</td>
    </tr>
  </table>
  <div>
    <button data-controller="table-action" data-action="table-action#add"
      data-table-action-url-param="https://path.to.tables/">
      Add row
    </button>
  </div>
</main>
Run Code Online (Sandbox Code Playgroud)
import { Controller } from '@hotwired/stimulus';

class TableController extends Controller {
  static targets = ['row', 'status'];

  show({ detail: { url } = {}, target }) {
    console.log('event.target - the button that triggered the click', event.target);
    if (url) {
      const rowCount = this.rowTargets.length;
      this.statusTarget.innerText = `Request from: ${url}, there are ${rowCount} rows.`;
    }
  }
}

export default TableController;
Run Code Online (Sandbox Code Playgroud)
import { Controller } from '@hotwired/stimulus';

class TableActionController extends Controller {
  add({ params }) {
    this.dispatch('add', {
      detail: { ...params },
      bubbles: true,
      cancelable: false,
    });
  }
}

export default TableActionController;
Run Code Online (Sandbox Code Playgroud)