Binding events to repeating elements


#1

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.


#2

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?


#3

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.


#4

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" ...
}

#5

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