I am just using Stimulus for the first time - and I am very happy with it. Thanks to all creators and contributors. During my usage I stumbled over one particular issue, I cannot wrap my head around:
How can I select a specific Stimulus-Target by a data-attribute, class or id?
Stimulus is providing me with the two target properties:
- this.[name]Target → returns first target element (but no way to select a specific target, which is not the first one)
- this.[name]Targets → returns the array of target-elements (but I don’t know, if (and how) I can select somehow from his array a specific element)
I have a list of 4 links and 4 paragraphs (both inside the scope of the Stimulus-Controller). When clicking the link, I want something to happen (e.g. adding a class) with the paragraph, which has the same data-id as the link. The paragraphs have been defined as Stimulus-Targets.
Please see here example code: Edit fiddle - JSFiddle - Code Playground
(this example is highly simplified to show the issue)
I want to avoid
document.querySelector(...) as the element with the data-id could be present on the page multiple times (see second list in the JS-Fiddle). Therefore, a solution within the “scope” of the Stimulus controller would be the preferred solution.
When you use
this.[name]Targets it returns an array of all the targets this means you can use Array methods like find or filter.
You can use either dataset attributes or the params API that was added in stimulus 3 to pass the paragraph id into the function
<a href="#" data-id="paragraph_1" data-paragraph-color-id-param="paragraph_1" data-action="paragraph-color#colorParagraph">
const paragraphId = e.params.id
const paragraph = this.paragraphTargets.find(target => target.dataset.id == paragraphId)
And it might be a good idea to try to follow the same rules as HTML when it comes to ID attributes. If you have elements in the same DOM that share a
data-id, that should be considered just as bad an idea as if they shared the same
id. There’s just no good way to disambiguate targets once you allow that to exist.
Thank you! I was thinking way too far but the solution was so near… Thanks for this hint.
Regarding the params: I tried them as well. But they are in my opinion “strangely unflexible”, as I cannot name them properly. I can explain this at my original issue: I am dealing with a picture gallery (controller is named gallery_controller), where I have to deal with thumbs (the link) and then the pictures (the paragraphs). If I would use here the params API, the params would be named: data-gallery-id-param - but as you can see, this would by highly missleading, as they should be named data-pictures-id-param or data-thumb-id-param… Therefore, I am using normal dataset attributes.
yes It is definitely good to use dataset attributes instead as its the same reliability using the params API just saves you a few lines of code