via Data Attributes
Trigger reflexes without writing any javascript with the data-reflex
attribute.
index.html.erb
<a
href="#"
data-reflex="click->CounterReflex#increment"
data-step="1"
data-count="<%= @count.to_i %>"
>Increment <%= @count.to_i %></a
>
counter_reflex.rb
class CounterReflex < StimulusReflex::Reflex
def increment
@count = element.dataset[:count].to_i + element.dataset[:step].to_i
end
end
from Stimulus.js Controller
Stimulus.js controllers registered with StimulusReflex can use the stimulate
method to trigger reflexes
index.html.erb
<a href="#"
data-controller="counter"
data-action="click->counter#increment"
>Increment <%= @count %></a>
counter_controller.js
import { Controller } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'
export default class extends Controller {
connect() {
StimulusReflex.register(this)
}
increment(event) {
event.preventDefault()
this.stimulate('Counter#increment', 1)
}
}
counter_reflex.rb
class CounterReflex < StimulusReflex::Reflex
def increment(step = 1)
session[:count] = session[:count].to_i + step
end
end
Morphs
Selector morphs
Instead of refreshing the entire page, you can specify a portion of the page to update with morph(selector, content)
<!-- show.html.erb -->
<header data-reflex="click->Example#change">
<%= render partial: "path/to/foo", locals: {message: "Am I the medium or the massage?"} %>
</header>
<!-- _foo.html.erb -->
<div id="foo">
<span class="spa"><%= message %></span>
</div>
# example_reflex.rb
class ExampleReflex < ApplicationReflex
def change
morph "#foo", "Your muscles... they are so tight."
end
end
Nothing morph
Use morph :nothing
in reflexes that do something on the server without updating the client.
# example_reflex.rb
class ExampleReflex < ApplicationReflex
def change
LongRunningJob.perform_later
morph :nothing
end
end
Lifecycle
Server-side callbacks
Reflex classes can use the following callbacks. Full Docs
before_reflex
around_reflex
after_reflex
Client-side callbacks (generic)
StimulusReflex controllers automatically support five generic lifecycle callback methods.
beforeReflex(element, reflex, noop, reflexId)
prior to sending a request over the web socketreflexSuccess(element, reflex, noop, reflexId)
after the server side Reflex succeeds and the DOM has been updatedreflexError(element, reflex, error, reflexId)
whenever the server side Reflex raises an errorreflexHalted(element, reflex, noop, reflexId)
reflex canceled with throw :abort in the before_reflex callbackafterReflex(element, reflex, noop, reflexId)
after both success and errorfinalizeReflex(element, reflex, noop, reflexId)
after both success and error
Client-side callbacks (custom)
StimulusReflex controllers can define up to five custom lifecycle callback methods for each Reflex action. These methods use a naming convention based on the name of the Reflex. e.g. for the add_one
reflex:
beforeAddOne(element, reflex, noop, reflexId)
addOneSuccess(element, reflex, noop, reflexId)
addOneError(element, reflex, error, reflexId)
addOneHalted(element, reflex, noop, reflexId)
afterAddOne(element, reflex, noop, reflexId)
finalizeAddOne(element, reflex, noop, reflexId)
Client-side events
If you need to know when a Reflex method is called, but you’re working outside of the Stimulus controller that initiated it, you can subscribe to receive DOM events
stimulus-reflex:before
stimulus-reflex:success
stimulus-reflex:error
stimulus-reflex:halted
stimulus-reflex:after
There are also events related to the StimulusReflex library setting up and connecting to ActionCable
stimulus-reflex:connected
stimulus-reflex:disconnected
stimulus-reflex:rejected
stimulus-reflex:ready
Helpful tips
Forms
If a Reflex is called on a form element - or a child of that form element - then the data for the whole form will be properly serialized and made available to the Reflex action method as the params
accessor. Read more
Promises
stimulate()
method returns a promise
this.stimulate('Comments#create')
.then(() => this.doSomething())
.catch(() => this.handleError())
Inheriting data-attributes from parent elements
You can use the data-reflex-dataset="combined"
directive to scoop all data attributes up the DOM hierarchy and pass them as part of the Reflex payload.
<!-- new.html.erb -->
<div data-post-id="<%= @post.id %>">
<div data-category-id="<%= @category.id %>">
<button data-reflex="click->Comment#create" data-reflex-dataset="combined">Create</button>
</div>
</div>
# comment_reflex.rb
class CommentReflex < ApplicationReflex
def create
puts element.dataset["post-id"]
puts element.dataset["category-id"]
end
end
Reflex root
Instead of updating your entire page, you can specify exactly which parts of the DOM will be updated using the data-reflex-root
attribute. Full docs
<!-- index.html.erb -->
<div data-reflex-root="[forward],[backward]">
<input type="text" value="<%= @words %>" data-reflex="keyup->Example#words">
<div forward><%= @words %></div>
<div backward><%= @words&.reverse %></div>
</div>
# example_reflex.rb
def words
@words = element[:value]
end
Permanent elements
Add data-reflex-permanent to any element in your DOM, and it will be left unchanged by full-page Reflex updates and morph calls that re-render partials.
<!-- index.html.erb -->
<div data-reflex-permanent>
<iframe src="https://ghbtns.com/github-btn.html?user=hopsoft&repo=stimulus_reflex&type=star&count=true" frameborder="0" scrolling="0" class="ghbtn"></iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=hopsoft&repo=stimulus_reflex&type=fork&count=true" frameborder="0" scrolling="0" class="ghbtn"></iframe>
</div>
Aborting a reflex
call raise :abort
within a reflex method to cancel it.
# comment_reflex.rb
class CommentReflex < ApplicationReflex
def create
raise :abort
end
end
0 Comments for this cheatsheet. Write yours!