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
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
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
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
Reflex classes can use the following callbacks. Full Docs
before_reflex
around_reflex
after_reflex
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 errorStimulusReflex 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)
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
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
stimulate()
method returns a promise
this.stimulate('Comments#create')
.then(() => this.doSomething())
.catch(() => this.handleError())
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
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
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>
call raise :abort
within a reflex method to cancel it.
# comment_reflex.rb
class CommentReflex < ApplicationReflex
def create
raise :abort
end
end
Subscribe to get resources directly to your inbox. You won't receive any spam! ✌️