I got a jQuery function that catches changes on a input field and add it to a variable.
The input field is also held up on a vanilla js based API lib, that I cant convert to jQuery.
The lib is an address API, so people can select a address, and that wont trigger my jQuery function. I therefore thought of a workaround, where my jQuery is watching my vanilla js, to see when it's fired, and fire my jQuery function right after.
My jQuery function:
$('#billing_address_1').on('input',function(e){
let addressValue = $('#billing_address_1').val();
});
My vanilla js function:
"use strict"
dawaAutocomplete.dawaAutocomplete( document.getElementById("billing_address_1"), {
select: function(selected) {
document.getElementById("valgtadresse").innerHTML = selected.tekst;
}
});
All solutions I've been able to search for, has been requiring that I use .trigger() on my vanilla js in this case. They've not been made for the mix of these two js alternatives. Can I do it in a more proper way?
If you don't want to touch your fields with trigger you can try event emitter pattern which is quite popular in node. Here you keep an object as notifier on which you call event and also hook listeners for that event. It is basically a Pub-Sub pattern a simple implementation of which in vanilla javascript is available over here by mudge or you might also try any alternatives if you find
// KEEP THIS SOMEWHERE IN OUTER SCOPE
let bird = new EventEmitter()
//THEN - hook on any event you name it
bird.on('tweet', (val)=>{
console.log(val)
addressValue = val
})
//THEN - emit that named event wherever you might need
dawaAutocomplete.dawaAutocomplete( document.getElementById("billing_address_1"), {
select: function(selected) {
document.getElementById("valgtadresse").innerHTML = selected.tekst;
bird.emit('tweet', selected.tekst);
}
});
So I ran into some Javascript weirdness if i write a function like this my passed callback works fine
messageHandler(callback) {
this.ws.onmessage = (data) => {
callback(data.data);
};
}
If you write like this
messageHandler(callback) {
this.ws.on('message', (data) => {
callback(data);
});
}
It mutates the callback into a message event I can't seem to figure out why but I'd like to understand this behavior if anyone can explain. Thanks in Advance.
I think the question omits crucial information but based on the code examples, I think you're using https://github.com/websockets/ws implementation, correct?
If so, then .ws.on('message', ... refers to Event Emitter listener. The params passed to your handler is the message or stream or whatever data object the emitter emits.
.ws.onmessage refers to the browser's Websocket API - so the parameter passed there is a MessageEvent. As you can see from the spec, data is a property on MessageEvent class which explains why you have to refer with 1 level of indirection as data.data.
Perhaps it'd be less confusing if you call your parameter event instead of data in the first example:
this.ws.onmessage = (event) => {
callback(event.data);
};
You can also view this as server side events vs. client side events - your first example is a client side event whereas the second example is a server side event. Client side events conform to Websockets API whereas server side events, in NodeJS world, typically use event emitters.
I'm working with a 3rd party product where I am extending the UI with my own custom functionality. Within part of that I need to call an event after the UI has been updated with an AJAX call. Luckily the app fires a call to a Custom Event using the Prototype JS library after the call is complete, like this:
$(document.body).fire("ns:customevent");
If I add my own custom event with the same name then this works as expected
$(document).observe("ns:customevent", function(event) {
//do custom stuff here
});
[I could not get $(document.body).observe() to work here but I don't think that really matters.]
My concern here is that there may be other parts of the app that have registered functions against that event, and I am (blindly) overwriting them with my own, which will lead to issues further down the line.
Does Prototype append custom functions even though they have the same name or does it in fact overwrite them? If it does overwrite them then how can I append my function to anything that is already existing? Is there anyway of viewing what
I would imagine something like this, but I hardly know Protoype and my JS is very rusty these days.
var ExistingCustomEvent = $(document.body).Events["ns:customevent"];
$(document).observe("ns:customevent", function(event) {
ExistingCustomEvent();
//do custom stuff here
});
I can't add my event handler or add in code to call my own function, I want to try avoiding the 3rd party library (if that would even be possible).
Thanks.
As an FYI for anyone else that stumbles upon this question, following the comment from Pointy it turns out that Prototype does append the functions to the custom event.
I verified this by trying the following and both alerts fired.
$(document).observe("ns:customevent", function(event) {
alert("ALERT 1");
});
$(document).observe("ns:customevent", function(event) {
alert("ALERT 2");
});
Great :)
My requirements
Because of the asynchronous architecture of my applications I am looking for an 'event' system which has the following two two properties:
The events should be able to fire multiple times (possible with events, but not with promises)
When I start listening for an event that has already been fired, I want the listener to fire once immediately (as with promises)
The reason for 1. is that there are a lot of events (e.g. the updating of certain data) that I want to be able to fire multiple times. But I would like to combine this with 2. so that if an event has already fired upon adding the listener, this listener gets called immediately. This is because I'm not always sure (and I don't want to be sure) which piece of code gets run first.
My 'solution'
I have thought up the following solution. I'm using this in an AngularJS application therefore the AngularJS context, but the question is applicable for Javascript in general. Note that I simplified the code.
app.controller('AppCtrl', function(CustomEventEmitter){
// Broadcast an event. No listener added so nothing happens
CustomEventEmitter.broadcast('event');
// Add the event listener. Because the event allready fired, the listener gets called immediatly
CustomEventEmitter.on('event', function(){
console.log('Event emitted');
});
// Broadcast an other event
CustomEventEmitter.broadcast('event');
});
app.service('CustomEventEmitter', function(){
var
listeners = {},
memory = [];
this.broadcast = function(name){
// The normal broadcasting of the event to the listener
if(listeners[name]) {
listeners[name].forEach(function(listener){
listener();
});
}
// Push the event into the 'memory'
memory.push(name);
};
this.on = function(name, listener){
// The normal adding of the listener
if(!listeners[name]) {
listeners[name] = [];
}
listeners[name].push(listener);
// If an event is already in memory, call the listener
if(memory.indexOf(name) !== -1) {
listener();
}
};
});
My questions
My questions are these:
What is the 'best practice' solution for my requirements?
What do you think of my 'solution'?
Am I missing something completely obvious?
The reason for the last question is that it seems to me that this is a very common design paradigm but I seem unable to find the best way to solve this in simple and concise way.
Note
I understand this can be solved with the adding of extra code (e.g. before adding the listener, check in an other way if the event you are going to listen for already happened) but this is not what I'm looking for.
A "property" from bacon.js does exactly what you are asking for. This falls under the broader category of functional reactive programming (FRP). The most popular two libraries for this in JavaScript are probably
bacon.js
Reactive Extensions
Both of which provide the specific tool you're asking for, along with a vast array of alternatives.
Are there any Event Driven Architecture jQuery plugins?
Step 1: Subscribing
The subscribers subscribe to the event handler in the middle, and pass in a callback method, as well as the name of the event they are listening for...
i.e. The two green subscribers will be listening for p0 events. And the blue subscriber will be listening for p1 events.
Step 2: The p0 event is fired by another component to the Event Handler
A p0 event is fired to the Event Handler
The event handler notifies it's subscribers of the event, calling the callback methods they specified when they subscribed in Step 1: Subscribing.
Note that the blue subscriber is not notified because it was not listening for p0 events.
Step 3: The p1 event is fired a component to the Event Handler
The p1 event is fired by another component
Just as before except that now the blue subscriber receives the event through its callback and the other two green subscribers do not receive the event.
Images by leeand00, on Flickr
I can't seem to find one, but my guess is that they just call it something else in Javascript/jquery
Also is there a name for this pattern? Because it isn't just a basic publisher/subscriber, it has to be called something else I would think.
You probably don't need a plugin to do this. First of all, the DOM itself is entirely event driven. You can use event delegation to listen to all events on the root node (a technique that jQuery live uses). To handle custom events as well that may not be DOM related, you can use a plain old JavaScript object to do the job. I wrote a blog post about creating a central event dispatcher in MooTools with just one line of code.
var EventBus = new Class({Implements: Events});
It's just as easy to do in jQuery too. Use a regular JavaScript object that acts as a central broker for all events. Any client object can publish and subscribe to events on this object. See this related question.
var EventManager = {
subscribe: function(event, fn) {
$(this).bind(event, fn);
},
unsubscribe: function(event, fn) {
$(this).unbind(event, fn);
},
publish: function(event) {
$(this).trigger(event);
}
};
// Your code can publish and subscribe to events as:
EventManager.subscribe("tabClicked", function() {
// do something
});
EventManager.publish("tabClicked");
EventManager.unsubscribe("tabClicked");
Or if you don't care about exposing jQuery, then simply use an empty object and call bind and trigger directly on the jQuery wrapped object.
var EventManager = {};
$(EventManager).bind("tabClicked", function() {
// do something
});
$(EventManager).trigger("tabClicked");
$(EventManager).unbind("tabClicked");
The wrappers are simply there to hide the underlying jQuery library so you can replace the implementation later on, if need be.
This is basically the Publish/Subscribe or the Observer pattern, and some good examples would be Cocoa's NSNotificationCenter class, EventBus pattern popularized by Ray Ryan in the GWT community, and several others.
Though not a jQuery plugin, Twitter released a JavaScript framework called Flight which allows you to create component-based architectures, which communicate via events.
Flight is a lightweight, component-based JavaScript framework from Twitter. Unlike other JavaScript frameworks which are based around the MVC pattern, Flight maps behavior directly to DOM nodes.
Flight is agnostic to how requests are routed or which templating library you decide to use. Flight enforces strict separation of concerns. Components in Flight do not engage each other directly.
They broadcast their actions as events and those components subscribed to those events can take actions based on them. To make use of Flight, you will need the ES5-shim and jQuery along with an AMD loader.
Flight - A Lightweight, Component-Based JavaScript Framework From Twitter
There are actually two of them:
Listen (faster): http://plugins.jquery.com/project/Listen
Intercept (more advanced): http://plugins.jquery.com/project/Intercept
Could this serve as a ligthweight message passing framework?
function MyConstructor() {
this.MessageQueues = {};
this.PostMessage = function (Subject) {
var Queue = this.MessageQueues[Subject];
if (Queue) return function() {
var i = Queue.length - 1;
do Queue[i]();
while (i--);
}
}
this.Listen = function (Subject, Listener) {
var Queue = this.MessageQueues[Subject] || [];
(this.MessageQueues[Subject] = Queue).push(Listener);
}
}
then you could do:
var myInstance = new MyConstructor();
myInstance.Listen("some message", callback());
myInstance.Listen("some other message", anotherCallback());
myInstance.Listen("some message", yesAnotherCallback());
and later:
myInstance.PostMessage("some message");
would dispatch the queues
This can easily be accomplished using a dummy jQuery node as a dispatcher:
var someModule = (function ($) {
var dispatcher = $("<div>");
function init () {
_doSomething();
}
/**
#private
*/
function _doSomething () {
dispatcher.triggerHandler("SOME_CUSTOM_EVENT", [{someEventProperty: 1337}]);
}
return {
dispatcher: dispatcher,
init: init
}
}(jQuery));
var someOtherModule = (function ($) {
function init () {
someModule.dispatcher.bind("SOME_CUSTOM_EVENT", _handleSomeEvent)
}
/**
#private
*/
function _handleSomeEvent (e, extra) {
console.log(extra.someEventProperty) //1337
}
return {
init: init
}
}(jQuery));
$(function () {
someOtherModule.init();
someModule.init();
})
A recent development is msgs.js "Message oriented programming for JavaScript. Inspired by Spring Integration". It also supports communication via WebSockets.
msgs.js applies the vocabulary and patterns defined in the 'Enterprise Integration Patterns' book to JavaScript extending messaging oriented programming into the browser and/or server side JavaScript. Messaging patterns originally developed to integrate loosely coupled disparate systems, apply just as well to loosely coupled modules within a single application process.
[...]
Tested environments:
Node.js (0.6, 0.8)
Chrome (stable)
Firefox (stable, ESR, should work in earlier versions)
IE (6-10)
Safari (5, 6, iOS 4-6, should work in earlier versions)
Opera (11, 12, should work in earlier versions)
I have used the OpenAjax Hub for its publish/subscribe services. It's not a jQuery plugin, but a standalone JavaScript module. You can download and use the reference implementation from SourceForge. I like the hierarchical topic naming and the support for subscribing to multiple topics using wildcard notation.