英文:
Rails 7/Stimulus: How do I reference an element with a dynamically generated ID from within a controller action?
问题
我有一个Entry
模型。我使用一个部分渲染每个条目。在每个条目下面,我有一个按钮。单击该按钮会在一个turbo框架中显示完整的条目。
当turbo框架加载时,在stimulus控制器中触发了#toggle
动作。Rails使用dom_id(entry, :show)
为每个按钮生成唯一的id(例如show_entry_1000529641
)。
我想在#toggle
动作中引用按钮元素。
我理解通常引用目标的方式是首先在顶部声明它们的静态目标static targets = [...]
。但由于目标id是动态生成的,我不确定该怎么做。
目前,我在turbo框架上设置了一个data-button
属性。然后使用该值查找按钮元素。
我觉得可能有更好的方法。正确/更好的方法是什么?
#entries/_entry.html.erb
#...
<%=
button_to "Show #{entry}",
entry_path(entry),
id: dom_id(entry, :show),
method: :get,
data: { turbo_frame: dom_id(entry) } %>
#...
<%= turbo_frame_tag entry,
data: {
controller: "buttons",
action: "turbo:frame-load->buttons#toggle",
button: dom_id(entry, :show)
} %>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
toggle() {
const button_id = this.element.getAttribute('data-button')
const button = document.getElementById(button_id)
console.log(button)
}
}
英文:
I have an Entry
model. I render each entry using a partial. Below each entry, I have a button. Clicking on that button shows the complete entry within a turbo frame.
When the turbo frame loads, the #toggle
action is fired in the stimulus controller. Rails generates a unique id for every button using dom_id(entry, :show)
. (show_entry_1000529641
for example).
I want to reference the button element in the #toggle
action.
I understand that the usual way of referencing targets is by first declaring them at the top static targets = [...]
. But since the target ids are generated dynamically, I'm not sure what to do.
At the moment, I am setting a data-button
attribute on the turbo frame. Then using that value to look up the button element.
I feel like there is probably a better way of doing this. What is the correct/better way?
#entries/_entry.html.erb
#...
<%=
button_to "Show #{entry}",
entry_path(entry),
id: dom_id(entry, :show),
method: :get,
data: { turbo_frame: dom_id(entry) } %>
#...
<%= turbo_frame_tag entry,
data: {
controller: "buttons",
action: "turbo:frame-load->buttons#toggle",
button: dom_id(entry, :show)
} %>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
toggle() {
const button_id = this.element.getAttribute('data-button')
const button = document.getElementById(button_id)
console.log(button)
}
}
答案1
得分: 1
以下是翻译好的部分:
"The Targets use a name as a reference, not an ID (see documentation)"
目标使用名称作为引用,而不是 ID(参见文档)
"The correct Stimulus approach is to have all necessary elements inside the controller and reference these using Target names. The controller <div>
acts as a scope therefore you can have multiple same name controllers with same name targets in one page and it would just work, no need for element IDs."
正确的 Stimulus 方法是将所有必要的元素放在控制器内,并使用目标名称引用这些元素。控制器 <div>
充当作用域,因此您可以在页面中拥有多个相同名称的控制器和相同名称的目标,而不需要元素 ID。
"There where you would normally use a reference by ID, use this.exampleTarget
in Stimulus. An analogy for a reference by a class is this.exampleTargets
. Targets must be defined in the static targets = ['example']
and in the element's data attribute data-controllerName-target="example"
在通常会使用 ID 引用的地方,在 Stimulus 中使用 this.exampleTarget
。使用类引用的类比是 this.exampleTargets
。目标必须在 static targets = ['example']
中定义,并在元素的数据属性 data-controllerName-target="example"
中定义。
"I suggest you try something like this:"
我建议您尝试类似以下的代码:
#entries/_entry.html.erb
#...
<div data-controller="buttons">
<%=
button_to "Show #{entry}",
entry_path(entry),
id: dom_id(entry, :show),
method: :get,
data: { turbo_frame: dom_id(entry),
buttons_target: 'button'
} %>
#...
<%= turbo_frame_tag entry,
data: {
action: "turbo:frame-load->buttons#toggle",
button: dom_id(entry, :show)
} %>
</div>
import { Controller } from "@hotwired/stimulus"
static targets = ['button']
export default class extends Controller {
toggle() {
console.log(this.buttonTarget)
}
}
<details>
<summary>英文:</summary>
The Targets use a name as a reference, not an ID (see [documentation][1])
The correct Stimulus approach is to have all necessary elements inside the controller and reference these using Target names. The controller `<div>` acts as a scope therefore you can have multiple same name controllers with same name targets in one page and it would just work, no need for element IDs.
There where you would normally use a reference by ID, use `this.exampleTarget` in Stimulus. An analogy for a reference by a class is `this.exampleTargets`. Targets must be defined in the `static targets = ['example']` and in the element's data attribute `data-controllerName-target="example"`
I suggest you try something like this:
```erb
#entries/_entry.html.erb
#...
<div data-controller="buttons">
<%=
button_to "Show #{entry}",
entry_path(entry),
id: dom_id(entry, :show),
method: :get,
data: { turbo_frame: dom_id(entry),
buttons_target: 'button'
} %>
#...
<%= turbo_frame_tag entry,
data: {
action: "turbo:frame-load->buttons#toggle",
button: dom_id(entry, :show)
} %>
</div>
import { Controller } from "@hotwired/stimulus"
static targets = ['button']
export default class extends Controller {
toggle() {
console.log(this.buttonTarget)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论