Reputation: 16373
I have a Stimulus controller
# app/javascript/controllers/clubs_controller.js
// handles micropost javascripts
import { Controller } from "stimulus"
import Rails from '@rails/ujs';
export default class extends Controller {
connect() {
}
wait_for_clubs(event) {
event.preventDefault()
console.log("in wait_for_clubs", event.target)
const id = event.target.dataset.value
console.log("id", id)
}
}
}
and html code
<div data-controller="clubs">
<span data-action="load@window->clubs#wait_for_clubs" data-value='<%= @user.id %>'>Waiting for Clubs to be prepared</span>
</div>
with the idea that when the page is loaded, the controller has the id of the user. When I reload the page, I see the following error in the console
TypeError: Cannot read property 'value' of undefined
which is triggered by the var id = event.target.dataset.value;
statement.
However if I change the event from load@window
to click
, then when I click the span, the code works and retrieves the id. How do I fix this?
Upvotes: 17
Views: 31988
Reputation: 14275
Things have changed a bit since the currently accepted answer was submitted.
The docs now advise against reading data attributes directly (this.data.get("myValue")
):
This might get the job done, but it’s clunky, requires us to make a decision about what to name the attribute, and doesn’t help us if we want to access the index again or increment it and persist the result in the DOM.
Instead, declare the values on the controller itself. Doing so has the added benefit of coercing the attribute to the specified type:
<div data-controller="slideshow" data-slideshow-index-value="1">
export default class extends Controller { static values = { index: Number } initialize() { console.log(this.indexValue) console.log(typeof this.indexValue) } // … }
Upvotes: 4
Reputation: 431
If you are trying to pass data to a Stimulus controller that exists on the DOM when it loads, the Stimulus docs recommend using the built-in data API.
In your case, that would mean adding a data-clubs-my-value
attribute to the DOM element where you assign the data-controller
attribute, like so:
<div data-controller="clubs"
data-clubs-my-value="<%= @user.id %>">
</div>
and then you can get this value from your Stimulus controller by calling this.data.get("myValue")
As to why data-action
didn't work...
The Stimulus docs do allow for Global Events so this event is being triggered. But when this happens, the triggering event.target
is window
, not your <span>
, so when you call event.target.dataset
, it is looking for the dataset of the window
, which does not have your value.
If you want an action in your Stimulus controller to fire upon page load, the best way to handle this is generally by using the connect()
method.
Upvotes: 32