I'm attempting to build a "notification system" of sorts for a broadcasting overlay. Essentially I catch events, add them to an array, then I run a function that observes that array. Each time an event is added, I run an animation that takes a given amount of time, remove that from the array and then move onto the next one.
I found that debounce
gets me a part of the way there. I'm able to add any number of events while the animations are running and it's able to empty the queue.
Problem being, I have to wait that specified time (in this case 5 seconds) before the first event is handled. However, when I set debounce to be immediate, everything breaks in that the first event will be immediately handled, but nothing else will.
# Pool handling.
pool: []
# Function adds events to the pool array.
addEventToPool: (event, data) ->
console.log "added #{event} with #{data} to pool!"
@get('pool').pushObject(data)
# Function that observes the pool array and runs debounce
# if there are any items in the pool.
observePool: (->
Ember.run.debounce(@, @handleEvent, 5000, false) if @get('pool').length
).observes('pool.[]')
# Event handling.
handleEvent: ->
pool = @get('pool')
object = pool.get('firstObject')
@set('payload', object)
Ember.$(".event-message__#{object.event}").addClass('active')
Ember.run.later (->
Ember.$(".event-message__#{object.event}").removeClass('active')
pool.removeObject(object)
), 2000
console.log "Number of remaining objects: #{pool.length}."
console.log "Objects remaining: #{JSON.stringify pool}."
I have a feeling that I need to move off of debounce
to fix this, but I'm not sure what that solution is.
Please let me know if you need any clarification!
The purpose of Ember.run.debounce
is to only run something once if debounce
has not been called in the last X seconds
.
It's main uses are for things like kicking off some type of action after a user has finished typing - so on every character someone is typing you could call Ember.run.debounce(handleInput, 1000)
and you can be sure that no matter how many times they press a key, your function will only run once - after they haven't pressed a key for 1 second.
It's also useful for handling scroll events - where there are lets say hundreds of scroll events when scrolling on a page but you only want to do some action once the scrolling has stopped - calling debounce
hundreds of times doesn't run it until you've stopped calling debounce
for the timeout
value (e.g. 100ms after the last scroll event in this case).
This seems a little bit different to what you're trying to do.
I think what you want to do is use Ember.run.later. You could combine it all into one function that simply observes pool.firstObject - since you're always pulling the first object and removing it once you're done.
handleEvent: Ember.observer('pool.firstObject', function() {
var pool = this.get('pool');
var obj = pool.get('firstObject');
if (obj) {
// add class
Ember.$(".event-message__#{object.event}").addClass('active');
// schedule remove class for 2 seconds from now
Ember.run.later(function() {
Ember.$(".event-message__#{object.event}").removeClass('active');
}, 2000);
// schedule remove object from pool 5 seconds from now
Ember.run.later(function() {
pool.removeObject(obj);
// after you've removed this object (which was firstObject)
// pool.firstObject will change, and the handleEvent function
// will get kicked off again
}, 5000);
}
})