0

Desired scenario:


Within source file A.html, element A's onclick handler is coded to trigger a custom event every time A is clicked.

Within source file BCD.js elements B, C & D (which were unknown at the time that element A was coded) want to subscribe/handle/respond/react to the custom event triggered by A's onclick handler function.


In this case from A's perspective B, C & D are anonymous receivers of the custom event.

Josh Beam
  • 19,292
  • 3
  • 45
  • 68
Neoheurist
  • 3,183
  • 6
  • 37
  • 55
  • possible duplicate of [how to implement observer pattern in javascript?](http://stackoverflow.com/questions/12308246/how-to-implement-observer-pattern-in-javascript) – Ted Hopp Jun 16 '15 at 23:39
  • 1
    Likewise, I'm having a hard time understanding what you example means. A html filename has nothing to do with any single element, and JavaScript has no HTML elements in it unless you first write code to make that happen, so: can you reword your question to use a less cryptic example, with normal names for things, and actual HTML and JS code you're imagining, so we can at least have something we can talk about in comments/answers? – Mike 'Pomax' Kamermans Jun 16 '15 at 23:39
  • 1
    No. In A's perspective, there are no B, C & D, there's just an element that an event can be triggered on. It does know nothing about subscribers. – Bergi Jun 16 '15 at 23:39
  • this meets my need: http://jsfiddle.net/Neoheurist/ncv6ufkh/ – Neoheurist Jun 17 '15 at 21:39

2 Answers2

1

You can do some sort of pubsub implementation.

var events = {};

var pubsub = {
    on: function(event, handler) {
        if(event in events) {
            events[event].push(handler);
        } else {
            events[event] = [handler];
        }
    },
    emit: function(event) {
        if(event in events) {
            events[event].forEach(function(handler) {
                handler.call(null, event);
            });
        }
    }
};

This sort of implementation ties custom events to a global object, so elements don't have to "know" about each other, like you mentioned. The way you'd implement the above would be something like:

document.getElementById('some-element').addEventListener('click', pubsub.emit.bind(null, 'custom-event'));

The click will emit an event, and any handlers will be called. So in some other module, or whatever, based on whatever action you prescribe, you can tie a handler to that event emission:

pubsub.on('custom-event', doSomething);

function doSomething() { ... }

I think this is a pretty normal, language-agnostic global event-handling implementation.

There are lots of ways that JavaScript developers have figured out how to handle this.

Josh Beam
  • 19,292
  • 3
  • 45
  • 68
  • `document.getElementById('some-element')` ... does it matter which element the event listener is added to (e.g. are there scoping rules)? For instance if the event listener were added to a leaf `

    ` within the DOM would the visibility / accessibility be any different than if the event listener were attached to the `

    ` element? if it doesn't matter, what would be a best practice?
    – Neoheurist Jun 17 '15 at 14:25
  • 1
    @Neoheurist, The native click event can only be seen by parents and children of the event target (events bubble up/down, depending on different circumstances.) However, the global event `custom-event` would be broadcast as part of the global `pubsub` object, which could be seen by, for example, a leaf `

    ` as you mention. Basically, by attaching the `pubsub` emission as a handler for the native `click`, you're forcing the click event to become "global", in a sense.

    – Josh Beam Jun 17 '15 at 14:27
  • so the event listener can be attached to any element within the document. --- my inclination would be to add all event listeners to the `` to emphasize the global scope (not that there would be any functional value to do this) --- does this sound reasonable? – Neoheurist Jun 17 '15 at 14:32
  • @Neoheurist, what you're suggesting makes sense in a theoretical sense, but it almost seems like an anti-pattern to me in a practical sense. My gut tells me there would be a better way to do it. A lot of these problems have been solved by MVC frameworks, for example. What is it that you're trying to do exactly? Are you working on a project, or were you just looking at it in a theoretical sense? – Josh Beam Jun 17 '15 at 14:36
  • It is a project and I'm on my own - so I apologize for picking nits - I have an edit button in a `
    ` that when clicked I want to activate an edit `
    ` by adding a class to it that causes the CSS to change the `
    ` from `display:none;` to `display:block;`... (changing any other `
    ` that might have been active to `display:none` in the process)
    – Neoheurist Jun 17 '15 at 14:41
  • @Neoheurist, handlers can still select non-hierarchical elements. `$('#edit-button').on('click', function() { $('#editable-div').toggleClass('hidden'); })` would work (you don't have to use jQuery, I just used it for brevity). – Josh Beam Jun 17 '15 at 14:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/80788/discussion-between-josh-beam-and-neoheurist). – Josh Beam Jun 17 '15 at 14:45
  • I've embellished the approach provided by Josh Beam - the important part of the exercise was creating variable names to establish a solid mental model regarding what's happening in the code: http://jsfiddle.net/Neoheurist/ncv6ufkh/ Thanks again Josh! – Neoheurist Jun 17 '15 at 21:38
  • @Neoheurist, interesting approach, I saw the jsfiddle! Glad you were able to find a way to make it work for you specific situation. – Josh Beam Jun 17 '15 at 21:41
1

First its important to differentiate between DOM events and the concept of events/pubsub in programming in general and the common javascript pattern.

DOM events are browser api to tell your javascript code that something have happened. they are also asyc

The custom events you are talking about are communication ways inside your javascript code, which is also referred to as 'events' Heres a basic implementation of such pattern http://davidwalsh.name/pubsub-javascript In the underline code its a simple sync function call

One more thing:
technically you can trigger DOM events with custom names and use that to communicate between different parts of you javascript code. i would advise agains that. That will also make the communication async

Bnaya
  • 765
  • 6
  • 15