Skip to content

Commit

Permalink
Do not debounce phx-blur
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismccord committed Jul 11, 2022
1 parent efd9b64 commit ebfebba
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 23 deletions.
11 changes: 7 additions & 4 deletions assets/js/phoenix_live_view/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ let DOM = {
document.title = `${prefix || ""}${str}${suffix || ""}`
},

debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, callback){
debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, callback){
let debounce = el.getAttribute(phxDebounce)
let throttle = el.getAttribute(phxThrottle)
if(debounce === ""){ debounce = defaultDebounce }
Expand Down Expand Up @@ -174,13 +174,16 @@ let DOM = {
} else {
callback()
this.putPrivate(el, THROTTLED, true)
setTimeout(() => this.triggerCycle(el, DEBOUNCE_TRIGGER), timeout)
setTimeout(() => {
if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER) }
}, timeout)
}
} else {
setTimeout(() => this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle), timeout)
setTimeout(() => {
if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle) }
}, timeout)
}


let form = el.form
if(form && this.once(form, "bind-debounce")){
form.addEventListener("submit", () => {
Expand Down
17 changes: 10 additions & 7 deletions assets/js/phoenix_live_view/live_socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -573,15 +573,15 @@ export default class LiveSocket {
let windowBinding = this.binding(`window-${event}`)
let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding)
if(targetPhxEvent){
this.debounce(e.target, e, () => {
this.debounce(e.target, e, browserEventName, () => {
this.withinOwners(e.target, view => {
callback(e, event, view, e.target, targetPhxEvent, null)
})
})
} else {
DOM.all(document, `[${windowBinding}]`, el => {
let phxEvent = el.getAttribute(windowBinding)
this.debounce(el, e, () => {
this.debounce(el, e, browserEventName, () => {
this.withinOwners(el, view => {
callback(e, event, view, el, phxEvent, "window")
})
Expand Down Expand Up @@ -614,7 +614,7 @@ export default class LiveSocket {
if(!phxEvent){ return }
if(target.getAttribute("href") === "#"){ e.preventDefault() }

this.debounce(target, e, () => {
this.debounce(target, e, "click", () => {
this.withinOwners(target, view => {
JS.exec("click", phxEvent, view, target, ["push", {data: this.eventMeta("click", e, target)}])
})
Expand Down Expand Up @@ -776,7 +776,7 @@ export default class LiveSocket {

DOM.putPrivate(input, "prev-iteration", {at: currentIterations, type: type})

this.debounce(input, e, () => {
this.debounce(input, e, type, () => {
this.withinOwners(dispatcher, view => {
DOM.putPrivate(input, PHX_HAS_FOCUSED, true)
if(!DOM.isTextualInput(input)){
Expand All @@ -789,15 +789,18 @@ export default class LiveSocket {
}
}

debounce(el, event, callback){
debounce(el, event, eventType, callback){
if(eventType === "blur" || eventType === "focusout"){ return callback() }

let phxDebounce = this.binding(PHX_DEBOUNCE)
let phxThrottle = this.binding(PHX_THROTTLE)
let defaultDebounce = this.defaults.debounce.toString()
let defaultThrottle = this.defaults.throttle.toString()

this.withinOwners(el, view => {
DOM.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, () => {
if(!view.isDestroyed() && document.body.contains(el)){ callback() }
let asyncFilter = () => !view.isDestroyed() && document.body.contains(el)
DOM.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, () => {
callback()
})
})
}
Expand Down
22 changes: 11 additions & 11 deletions assets/test/debounce_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe("debounce", function (){
let calls = 0
let el = container().querySelector("input[name=blur]")

DOM.debounce(el, {}, "phx-debounce", 100, "phx-throttle", 200, () => calls++)
DOM.debounce(el, {}, "phx-debounce", 100, "phx-throttle", 200, () => true, () => calls++)
DOM.dispatchEvent(el, "blur")
expect(calls).toBe(1)

Expand All @@ -46,7 +46,7 @@ describe("debounce", function (){
let el = container().querySelector("input[name=debounce-200]")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 0, "phx-throttle", 0, () => calls++)
DOM.debounce(el, e, "phx-debounce", 0, "phx-throttle", 0, () => true, () => calls++)
})
simulateInput(el, "one")
simulateInput(el, "two")
Expand All @@ -61,7 +61,7 @@ describe("debounce", function (){
let el = container().querySelector("input[name=debounce-200]")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 0, "phx-throttle", 0, () => calls++)
DOM.debounce(el, e, "phx-debounce", 0, "phx-throttle", 0, () => true, () => calls++)
})
simulateInput(el, "one")
simulateInput(el, "two")
Expand All @@ -76,7 +76,7 @@ describe("debounce", function (){
let el = container().querySelector("input[name=debounce-200]")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => calls++)
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => calls++)
})
simulateKeyDown(el, "1")
simulateKeyDown(el, "2")
Expand Down Expand Up @@ -108,7 +108,7 @@ describe("debounce", function (){
el.setAttribute("phx-debounce", "")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 500, "phx-throttle", 200, () => calls++)
DOM.debounce(el, e, "phx-debounce", 500, "phx-throttle", 200, () => true, () => calls++)
})
simulateInput(el, "one")
simulateInput(el, "two")
Expand All @@ -133,7 +133,7 @@ describe("debounce", function (){
let el = parent.querySelector("input[name=debounce-200]")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => calls++)
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => calls++)
})
el.form.addEventListener("submit", () => {
el.value = "submitted"
Expand All @@ -159,7 +159,7 @@ describe("throttle", function (){
let el = container().querySelector("#throttle-200")

el.addEventListener("click", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => {
calls++
el.innerText = `now:${calls}`
})
Expand Down Expand Up @@ -189,7 +189,7 @@ describe("throttle", function (){
el.setAttribute("phx-throttle", "")

el.addEventListener("click", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 500, () => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 500, () => true, () => {
calls++
el.innerText = `now:${calls}`
})
Expand Down Expand Up @@ -218,7 +218,7 @@ describe("throttle", function (){
let el = container().querySelector("input[name=throttle-200]")

el.addEventListener("input", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => calls++)
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => calls++)
})
el.form.addEventListener("submit", () => {
el.value = "submitted"
Expand All @@ -244,7 +244,7 @@ describe("throttle keydown", function (){
let el = container().querySelector("#throttle-keydown")

el.addEventListener("keydown", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => {
keyPresses[e.key] = (keyPresses[e.key] || 0) + 1
})
})
Expand All @@ -270,7 +270,7 @@ describe("throttle keydown", function (){
let el = container().querySelector("#throttle-keydown")

el.addEventListener("keydown", e => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => {
DOM.debounce(el, e, "phx-debounce", 100, "phx-throttle", 200, () => true, () => {
keyPresses[e.key] = (keyPresses[e.key] || 0) + 1
})
})
Expand Down
5 changes: 4 additions & 1 deletion guides/client/bindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ for example:
## Rate limiting events with Debounce and Throttle

All events can be rate-limited on the client by using the
`phx-debounce` and `phx-throttle` bindings, with the following behavior:
`phx-debounce` and `phx-throttle` bindings, with the exception of the `phx-blur`
binding, which is fired immediately.

Rate limited and debounced events have the following behavior:

* `phx-debounce` - Accepts either an integer timeout value (in milliseconds),
or `"blur"`. When an integer is provided, emitting the event is delayed by
Expand Down

0 comments on commit ebfebba

Please sign in to comment.