Comments (8)
Thanks for the positive feedback, @sosodev ! I'm glad that you were able to get Motion up and running 🎉
Currently, there is not any built-in way to debounce motions; however, if you're willing to write some JavaScript, the client does expose the ability to trigger motions programatically via motion.getComponent(element).processMotion(motion, event)
. Here is how that might look with Stimulus:
<input class="input" type="text" placeholder="Search" data-controller="example" data-action="input->search">
// app/javascript/controllers/example_controller.js
import { Controller } from "stimulus"
import motion from "../motion"
export default class extends Controller {
search(event) {
if (this.timeout) {
clearTimeout(this.timeout)
}
this.timeout = setTimeout(() => {
this.timeout = null
motion.getComponent(event.target).processMotion("search", event)
}, 1000)
}
}
This isn't really an answer to your question, but it is worth noting that if you used the change
event instead of input
, the motion would only be triggered once when the input looses focus instead of on each key press.
from motion.
Thanks for the info. :) Manually triggering the event seems like a good solution. I tend to avoid change events though since I think the idea of a focused input doesn't make any sense to the average user.
I'll go ahead and close this as solved. Hope you have a great weekend.
from motion.
Hi @alecdotninja, I found a slight problem while implementing this. Currently Motion attempts to serialize the currentTarget
for the event but currentTarget
is null by the time the debounced query fires and it causes an error.
Is there any particular reason why Motion chooses to provide both the target
and currentTarget
? I'm testing a naive patch that serializes the target
as the currentTarget
and it seems to work fine without requiring the API to change at all. Alternatively, allowing currentTarget
to be null would work too but might be a little confusing for new users who expect that value to always be set on the server side.
from motion.
Good catch, @sosodev . Thank you for being the trailblazer on this. 😄
The reason that we send currentTarget
(and indeed bless it as the default choice by aliasing it to Motion::Event#element
) is that this is the element to which the user added the data-motion
attribute, and it is likely where they have placed any other data attributes they want to use as "arguments" to their motion.
When writing that code, I didn't realize that currentTarget
could be null
(I thought it was always equivalent to this
inside of the event handler 😅).
I would gladly accept a patch to gracefully allow currentTarget
to be null
. That said, I think the ideal solution is actually to ditch currentTarget
completely, start sending the element to which the motion was bound, and expose that as Motion::Event#element
.
from motion.
Oh, I see what you mean. Determining the actual target element is a bit tricky. 😅
Maybe processMotion
could be modified to accept a motionElement
parameter, for custom stuff like debouncing, and query the component itself for the element when the motionElement
is null
.
I'm imagining it looking something like this...
// motion/javascript/Component.js
processMotion (name, event = null, motionElement = null) {
if (!motionElement) {
motionElement = this.element.querySelector(`[data-motion=${name}]`)
}
if (!this._subscription) {
this.client.log('Dropped motion', name, 'on', this.element)
return false
}
this.client.log('Processing motion', name, 'on', this.element)
const extraDataForEvent = event && this.client.getExtraDataForEvent(event)
this._subscription.perform(
'process_motion',
{
name,
event: event && serializeEvent(event, extraDataForEvent, motionElement)
}
)
return true
}
Modifying serializeEvent to emit our intended element like you mentioned
// motion/javascript/serializeElement.js
export default function serializeEvent (event, extraData = null, element = null) {
const { type } = event
const details = serializeEventDetails(event)
const target = serializeElement(event.target)
return {
type,
details,
extraData,
target,
element: element && serializeElement(element)
}
};
and simply doing away with current_target and the alias
# motion/lib/motion/event.rb
def element
return @element if defined?(@element)
@element = Motion::Element.from_raw(raw["element"])
end
This does seem like a cleaner solution. 😄 What do you think?
from motion.
Sorry for the delay, @sosodev 🙈 .
I like where this is going, but can we change the default in the case the element is not passed to something like this:
event.currentTarget || event.target.closest(`[data-motion=${name}]`)
I actually think the event.target.closest
approach will always give the right answer since (AFAIK) events only bubble up the DOM.
from motion.
In the next release of Motion, processMotion
will accept an optional 3rd argument for the Motion::Event#element
. 🎉 That said, my thinking on this issue has changed.
I think the ideal way to solve this problem is with something like debounced rather than hand-rolling the debouncing JavaScript. It turns out this approach works with or without #43.
from motion.
I'm going to go ahead and close this for now. Please feel free to reopen, @sosodev, if you have any questions or think something more should be done here. 😄
from motion.
Related Issues (20)
- Motion does not work on older IOS versions
- Motion v0.5.0 does not work with ViewComponent >= v2.35.0 HOT 1
- Consider changing the name? HOT 3
- [Question] What's the purpose of data-motion-key and -state? HOT 3
- [Question] Preventing unauthorized access to a resource's stream HOT 2
- It doesn't seem that Motion supports passing in a form builder object. HOT 1
- Slow application startup times in some projects HOT 24
- Intermittent exceptions when disconnecting a component and leaking memory HOT 10
- `session`, `cookies`, and `current_user` are only accessible while rendering HOT 5
- Motion component is unable to have a handle to a form object HOT 7
- Transpiled Event Serialization Issue HOT 1
- Add test helpers for generating events for testing
- Custom element attributes are lost on component re-render
- Events capture HOT 1
- [question] broadcast to multiple clients HOT 3
- Compatibility issue with Rails 6.1 ? HOT 12
- Domain lost after page change HOT 4
- Add better support for custom logging HOT 2
- Documentation: Clarify that info from request is lost after first re-render HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from motion.