Binding events to repeating elements

Hi there,

I’m currently struggling with the issue of binding events to an arbitrary number of repeating elements. I’m building a timeline (sort of a gantt, really) with the following structure:

<div class="timeline" data-controller="timeline">
    <div class="timeline__layers">
        <div class="timeline__layer">
            <div class="timeline__layer__event timeline__layer__event--range"
                 data-start="0800"
                 data-end="1200"
                 data-target="timeline.event"
                 data-action="click->timeline#showEventTooltip"
            >
                <div class="timeline__layer__event__content" data-target="foo">
                    Pie is yummy.
                </div>
            </div>
            <div class="timeline__layer__event timeline__layer__event--range"
                 data-start="1400"
                 data-end="1630"
                 data-target="timeline.event"
                 data-action="click->timeline#showEventTooltip"
            >
                <div class="timeline__layer__event__content" data-target="timeline.foo">
                    Cake is not pie.
                </div>
            </div>
        </div>
    </div>
</div>

The problem I am trying to solve hers is the showEventTooltip action. I’d prefer not do a lot of DOM traversing based on event.currentTarget, but I am not sure if there is another way. Ideally, I’d be able to provide a ‘context’ to a DOM node, which would allow me to sort-of “scope” my actions and targets.

<div class="timeline__layer__event timeline__layer__event--range"
	     data-start="1400"
	     data-end="1630"
	     data-target="timeline.event"
	     data-action="click->timeline#showEventTooltip"
	     data-context="event"
	>
	    <div class="timeline__layer__event__content" data-target="event.foo">
	        Pie is yummy.
	    </div>
</div>

Approaches that I can think of so far:

  • Create a separate controller for events. This feels like an easy solution, but also feels a bit weird because you’d quickly end up creating lots of controllers for everything.
  • Use generated actions and targets so that they are unique

I’d love to hear how other people are solving this issue and whether there is a way to make this work.

I’m not totally clear on the problem. Could you share what your action looks like? Is the issue that you want to read those data attributes from a parent element of the current target and treat them like arguments or parameters for the action?

My action is currently still empty because I am trying to solve the problem, but the idea is to show the timeline__layer__event__content when the parent element is clicked.

The idea is that once a timeline.event target is clicked, the corresponding timeline.foo element is shown.

For what you are describing, I would have a controller for each element like so:

<div class="timeline" >
    <div class="timeline__layers">
        <div class="timeline__layer">
            <div data-controller="timeline" class="timeline__layer__event timeline__layer__event--range"
                 data-start="0800"
                 data-end="1200"
                 data-action="click->timeline#showEventTooltip"
            >
                <div class="timeline__layer__event__content" data-target="timeline.content">
                    Pie is yummy.
                </div>
            </div>
            <div data-controller="timeline" class="timeline__layer__event timeline__layer__event--range"
                 data-start="1400"
                 data-end="1630"
                 data-action="click->timeline#showEventTooltip"
            >
                <div class="timeline__layer__event__content" data-target="timeline.content">
                    Cake is not pie.
                </div>
            </div>
        </div>
    </div>
</div>

and in your controller

showEventTooltip(e) {
      this.element.doSomething() // this.element = <div data-controller="timeline".....
      this.contentTarget.doSomething() //this.contentTarget = <div class="timeline__layer__event__content" ...
}

@arondeparon did that solve it? I am having the same problem.