Using Events to communicate between instances of a class.

@Jmv38 the second test does not appear to be successful. evMngr:off(“touch”) still triggers a touch event.

Fixed it. One request string uses instances. Then the check looks for subscriptions.

@Jmv38 Another feature that I find very useful in @Toadkick 's version is the use of “all” receiving all event triggers with the first param being the event that was triggered.

edit I added in “all” thats called with each trigger.

function EventMngr:trigger(name, ...)
    self.lastTrigger = name
    local evs = (self.events and self.events[name]) or {}
    for i,fa in ipairs(evs) do 
        local func,obj = fa.func, fa.obj
        if obj then func(obj,...) 
        else func(...) end
    end
    --trigger all
    local evs = (self.events and self.events["all"]) or {}
    for i,fa in ipairs(evs) do 
        local func,obj = fa.func, fa.obj
        if obj then func(obj,name,...) 
        else func(name,...) end
    end
end

About

Fixed it. One request string uses instances. Then the check looks for subscriptions.

I dont get it. I thought it worked in my test. But it doesn’t? what did you change to make it work? In my code?

if fn == nil then request = "remove all instances of this event" --This is correct
        else request = "remove this event" end
    elseif firstType == "function" then 
        fn = nameOrFnOrObj
        request = "remove all events with this function"
    else 
        obj = nameOrFnOrObj
        request = "remove all events with this object" 
    end

    if request == "remove all instances of this event" then --This had subscription instead of instances.

Adding an ‘all’ keyword is quite easy. But using @Toadkick class might be the best way for you

@jmv38 I added in “all” to the above post.

Ha i see! I changed the code be be clear and made this bug!

@Jmv38 I really have not found a need to have a class specific event manager and realized that I’ve mainly been using a global event manager. I’m liking your event manager very much.

But my example is a class!
I made a class because i though it would be better to have specialized evnt managers: 1 for draw, 1 for touch, 1 for object internals, because of speed reasons (going through a whole long table might be long?)

@Jmv38 you are right. I had been using @Toadkick 's Event manager incorrectly. I was extending each class I had which was un nessesary.

Added in a little function to extend a class with EventMngr using @Toadkick 's extend example.

function EventMngr.class()
        local target = class()    
        for k, v in pairs(EventMngr) do
            target[k] = v
        end
    return target
end

usage:
Obj = EventMngr.class()
function Obj:init()
...
end

First i though i would used @Toadkick extend function too.
And after i thought i could simply do:

Self.events = EventManager()

so i decided no to extend. But maybe i’ll go for your solution. I’ve not used the event manager yet, so i dont know what i really need.

After all, ‘all’ is a bit tricky to implemnt (you dont want events to fire twice)

@Jmv38 You never specifically fire “all”. “all” can be used as a catch all to view what events are being fired. I’ve been using all to track which and when events are fired. With the triggered event being passed as the first parameter its useful for tracking.

Just want to point out a few things:

  1. While I did port the code to Lua/Codea from backbone.js (taking some liberties here and there), nothing in there is really mine per se, and I don’t really take much credit for it. mainly I just tried to preserve all of the ideas from backbone.js implementation.

  2. With 1. in mind, because Backbone.Events was written to be very flexible and generic, so is the version of it that I have written in Lua. That’s what I consider to be the great thing about it. If you only need a global event broadcaster, you can just make a global event broadcaster. If you need arbitrary objects to be event broadcasters, you can have that too, with out having to write any “adapter” code. The code is consistent, and highly shareable. You just extend the Events object, and bam, now you can trigger and subscribe to (when I say “subscribe”, I mean calling the subscribe()/subscribeOnce() functions) events. As noted by @Briarfox, you only need to extend Events if you need to have trigger()/subscribe()/subscribeOnce() called on a given object. Additionally, the fact that you can do extend(class(), Events) is just a “bonus”; basically you provide the class with the Events interface, and all of the instantiated objects get to become broadcasters/subscribers.

Anyway, I’m not trying to convince anyone to use this or not; I actually think it’s great that you guys are exploring different ideas and learning the ins and outs yourselves. Really, you’ve only just scratched the surface :slight_smile: I just wanted to say a couple of things since I basically just barfed that code out there with very little explanation or example of how to use it, or what it’s capabilities are. I use this code (and code like this) because I do a lot of throwaway prototypes, and I need really reusable and flexible code. But my needs aren’t necessarily your needs, so take everything with a grain of salt :slight_smile:

EDIT: heh, also, I don’t really tend to use/write “managers” if I don’t have to, so that’s definitely a pattern you’ll see in code that I like to use (and write). “Managers” feel clunky and boiler-plate-y to me; I prefer to abstract away the need for them if/when I can. Maybe it has to do with my generally ambivalent attitude toward authority :smiley:

Glad that my code was useful, most often best to use code you understand. I ignore that sometimes when I find magic math to solve problems for me :slight_smile:

@Toadkick thanks for your advices.

@Jmv38 - It’s not missing the ability to have several registers to the same event, a signal is the event type itself, it’s a sort of strongly typed event, and you create one signal by event type. Sure it’s clearly not designed to handle global dispatching of multiple events, rather dedicated events channels. Glad to see you have started to write your own. To forgive me for making you go round into circle, I paste the event system I use inside a display list, just as example, because I needed the abilty to control the propagation. Read other implementations and write your own is clearly a good choice :slight_smile:

Emitter = {} Emitter.__index = Emitter

-- Basic event dispatcher
-- Only one callback allowed by instance/event type

function Emitter:init()
    self._listens = {}
end

function Emitter:emit( name, ... )
    -- Dispatch an event off event type name
    -- Return false from a listener callback to stop propagation
    -- @param string event name
    -- @param vararg data to broadcast
    -- @return true if the event was dispatched to all listeners

    local lisn = self._listens[name]
    if not lisn then
        return nil end
    
    for k,v in pairs(lisn) do
        if v then
            if v(k,...) == false then
                return false end
        else
            if k(...) == false then
                return false end
        end
    end
    return true
end

function Emitter:on( name, callback, scope )
    -- Register an event listener with this emitter
    -- @param string event type to listen to
    -- @param function the listener function
    -- @param table (optional) listener scope

    if not self._listens[name] then
        self._listens[name] = {}
    end
    self._listens[name][scope or callback] = scope and callback or false
end

function Emitter:off( name, target )
    -- Remove a listener from this emitter
    -- @param string event type
    -- @param function or object scope (optional) to remove. If not given
    -- remove all listeners of event type

    if not target then
        self._listens[name] = nil
        return end
    
    local lisn = self._listens[name]
    lisn[target] = nil
    for _,v in pairs(lisn) do
        return end

    self._listens[name] = nil
end

function Emitter:haslistener( name )
    -- Return registered listeners flag for event type name

    return self._listens[name] ~= nil
end

I’ve started rewriting my buttons library with the event model.
Ahhhhhhh… That feels so gooooooood!
I wish i had bumbed into that concept before.
Thanks at @briarfox for starting the discussion, and to the others for feeding it!

@Jmv38 Can’t wait to see it! I love your button class, so simple to add buttons when testing.