SignalR JavaScript client universal trigger - javascript

I need to attach an event to every hub.client method.
For example:
Hub.client.doSomething = function (e) {
aFunction(e);
};
Hub.client.doSomethingElse = function (e) {
aFunction(e);
};
Is there a way to attach aFunction() to all client methods on the client level, without placing the function in each client method?

I don't know about such callback available directly on hub proxy, but you could use received callback on connection object. (see list of connection lifetime events and received definition)
Be aware that received callback is called every time data is received by connection, this means, that if you have multiple hubs, it will be invoked when any of hub send data to client. This means, that you will have to inspect data received in callback and decide, if you should process this data (if it belongs to given hub, if it is real message, or just signalr internal message).

With some JavaScript code you can achieve what you need, regardless of what SignalR provides out of the box:
var extend = function (proxy, ex) {
var keys = Object.keys(proxy.client),
aop = function (p, k, f) {
var prev = p[k];
return function () {
f();
prev.apply(p, arguments);
};
};
keys.forEach(function (k) {
proxy.client[k] = aop(proxy.client, k, ex);
});
};
extend(Hub, aFunction);
It is enough to call the extend function on all your hub proxies after having defined your real handlers.
With some more effort this code can be made more solid and generic, but I think it should already put you in the right direction.

Related

Using SignalR in full ajax navigated web pages?

I'm trying to accommodate myself to SignalR.
But I need a gold point to completely understand it. I feel one step away from snatch...
My codes:
Javascript:
$(function() {
var connection = $.connection.signalR;
connection.client.broadcastTotalOnline = function (totalOnlineUser) {
$('#TotalOnline').html(totalOnlineUser);
};
$.connection.hub.start().done(function() {
console.log("Connection Started!");
});
});
C#:
public class SignalR : Hub
{
public void SendTotalOnline()
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalR>();
using (var dbContextx = new db_Oyun())
{
while (true)
{
int totalOnlineUser = dbContextx.tbl_User.Count(x => x.Online);
context.Clients.All.broadcastTotalOnline(totalOnlineUser);
Thread.Sleep(1000);
}
}
}
}
Above codes are work perfect but when I call new page to inner content with AJAX.
And then I would like to use same hub, same object and same hub, different object. It not working. Not calling alert; but when I removed above signalR codes, under codes working.
$(function () {
var connection = $.connection.signalR;
connection.client.broadcastTotalOnline = function (totalOnlineUser) {
alert(totalOnlineUser);
};
});
When you start your SignalR connection, it examines the $.connection.signalR.client object to see if you added any callbacks. If you add a callback using normal assignment after the connection has started, SignalR will not pick up that callback.
To add a callback after the connection has started, you can use $.connection.signalR.client.on:
$.connection.signalR.client.on("broadcastTotalOnline", function (totalOnlineUser) {
alert(totalOnlineUser);
});
If you were trying to add a callback to a Hub you didn't already have a callback for before starting your connection, then even using .on would not work.
You must have at least one callback hooked up to every hub you plan to use before you start up your connection. The callback that you setup can be a dummy callback that is never called. Adding the callback is just you way of indicating to SignalR that your interested in messages originating from that hub.
You don't need to add any dummy callbacks in your case since you already attach to broadcastTotalOnline before starting the connection.
If you want to remove a callback, you can use $.connection.signalR.client.off with a reference to the function you previously added:
var callback = function (totalOnlineUser) {
alert(totalOnlineUser);
};
$.connection.signalR.client.on("broadcastTotalOnline", callback);
$.connection.signalR.client.off("broadcastTotalOnline", callback);

Alternative for Javascript this object

I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});

Singleton Websockets object with different callback handlers

I have a JavaScript Websockets implementation where I would like to use a singleton model that uses one Websocket connection for multiple calls to the server but with different callback event handlers. I have the implementation working just fine but have noticed some strange behaviors with messages being directed to the wrong callback handler. Here is some code:
Connection.js file
var connection = function(){
var _socket = null;
return {
socket : function(){
if (_socket == null){
_socket = new WebSocket("ws://localhost:8081/index.ashx");
_socket.onclose = function(evt){alert('Closed');}
_socket.extraParameter = null;
}
return _socket;
},
send : function(data, callback){
var localSocket = connection.socket();
localSocket.extraParameter = new Date().toString();
localSocket.onmessage = callback;
localSocket.originalDataSent = data;
localSocket.send(data);
}
}
}();
App.js file
var App = function(){
return {
cpuUtilization : function(evt){
var localSocket = this;
var dateTimeOfRequest = localSocket.extraParameter;
var originalDataSent = localSocket.originalDataSent
var jsonData = $.parseJSON(evt.data);
if ($.parseJSON(originalDataSent).type == "cpu"){
$("#dateTimeContainer").html();
$("#cpuContainer").html(jsonData.value);
}
}
}
}();
Third Party Signal.js file
var Signal = function(){
return {
handlerProcess : function(evt){
// Does some third party stuff...
}
}
}();
usage
connection.send("{type:'process'}", Signal.handlerProcess);
connection.send("{type:'cpu'}", App.cpuUtilization);
connection.send("{type:'memory'}", Signal.handlerMemory);
connection.send("{type:'harddrive'}", Signal.handlerHardDrive);
Now where I think I am see the problem is when multiple request are made through the same websocket and the message returns. Since this is asynchronous, I have no way of tieing the request to the event callback. My solution uses the options in the handler for reference, but depending on the time it takes for the websocket request to run, the wrong callback handler is being called and process fails. I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.
Is there a way to pass a reference or additional parameters along with the evt parameter? Maybe wrapping this somehow?
I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.
Yes.
Since this is asynchronous, I have no way of tieing the request to the event callback.
No. You can create a closure for the callback function instead of calling using callback directly:
... send: function(data, callback){
var localSocket = connection.socket();
var extraParameter = new Date().toString();
localSocket.onmessage = function(evt) {
callback(evt.data, /* original- */ data, extraParameter);
};
localSocket.send(data);
}
But still, you have a changing onmessage callback handler. That means, an event may be sent to a handler that does not deserve it. Having an asynchronous system, you will need to add a piece of information to the server resonse that indicates which process the data belongs to. The one universal message handler then could resolve that and call the right callback.

Usage of Observable pattern in JavaScript

function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
var fn = function() {};
var o = new Observer;
o.subscribe(fn);
o.fire('here is my data');
o.unsubscribe(fn);
I am not able to understand the whole concept behind this. I want to implement this pattern in my project. I have a view where the form gets submitted and it calls an WebService and returns me response.
If i have to implement this in my project where this a simple request and response... how would i go about with it? i understand you notify your observer when there is a change... let's take i make a request to my API and i get the response back... now i want it to get notified to my view back through observable pattern
Observer appears to be a constructor that you call with var o = new Observer(); then o will be an object with a reference to a bunch of functions. you add functions to the list via subscribe. and remove them from the list via unsubscribe
then the whole point of it all is the "fire" method which will loop through the function list then call each of the functions one by one . "observer pattern" appears to be a lot like the singleton pattern
Are you familiar with the "watch" method in JavaScript? its a method supported via Firefox that you can use on any object.
document.myform.myfield.watch('value', function (v) {
alert(v);
return v;
})
then whenever the value of the object changes, the watch function is called. so basically the concept behind the observer pattern is that you want to basically simulate Firefox's watch method in a cross-browser fashion
you toss a reference to a bunch of functions or objects into subscribed list.then have Observer.fire call a callback method on each of the watched objects or functions. that way if the user preforms some sort of action such as clicking, then the whole list of functions would be updated via a callback function
I hope this helps.
If you only want to do a simple request then in jQuery (such as with $.ajax(...) or $.get(...)) that would look like this:
var requestUrl = "text.html";
// Callback is defined here
var viewCallback = function(data) {
// this will be called when the request is done
console.log('view is notified');
console.log('data looks like this:');
console.log(data);
// you could chain method calls to other callbacks here if you'd like
};
// Request is done here
$.ajax({
url: requestUrl,
}).done(viewCallback);
Most of the time you only want to do one thing when doing a request for which the above is enough code. Using javascript libraries such as jQuery or mootools will abstract away the oddities with the XMLHttpRequest object.
However if you want to do something much more advanced I'd recommend you look at libraries that do this sort of thing such as Radio.js.

Extending every Ajax.Request onSuccess event (Javascript Prototype Framework)

I have an application that uses Ajax.Request and its onSuccess event handler in lots of places.
I need to call a function (that will check the response) before all these onSuccess events fire. I tried using Ajax.Responders.register with onComplete event but it fires after Ajax.Request's onSuccess event. Any suggestions?
similar to Aleksander Krzywinski's answer, but I believe this would prevent you from having to sprinkle the use of "wrap" everywhere, by consolidating it to the onCreate Responder.
Ajax.Responders.register({
onCreate: function(request) {
request.options['onSuccess'] = request.options['onSuccess'].wrap(validateResponse);
}
});
There are several events to chose from. Here is the event chain for Ajax.Request:
onCreate
onUninitialized
onLoading
onLoaded
onInteractive
onXYZ, onSuccess or onFailure
onComplete
onLoading, onLoaded, onInteractive sound interesting, but according to the spec they are not guaranteed to happen. That leaves you with the possibility to hook on to onCreate, which is called just after the request object is build, but before the request is actually made.
This might be a little late, but for the benefit of anyone else wondering about the same problem I will propose this solution:
You can use Prototypes own implementation of aspect-oriented programming to do this. Granted you will have to modify all your onSuccess-parameters, but it can be done with a simple search-and-replace, instead of updating all your callback functions. Here is an example Ajax.Request creation:
new Ajax.Request('example.html', {
parameters: {action: 'update'},
onSuccess: this.updateSuccessful
});
Say you have similar code snippets spread all over your code, and you want to preceed them all with a certain function that validates the response before the actual function is run(or even prevented from running at all). By using Funtion.wrap supplied in Prototype we can do this by extending the code above:
new Ajax.Request('example.html', {
parameters: {action: 'update'},
onSuccess: this.updateSuccessful.wrap(validateResponse)
});
Where 'validateResponse' is a function similar to this:
// If you use the X-JSON-header of the response for JSON, add the third param
function validateResponse(originalFn, transport /*, json */) {
// Validate the transport
if (someConditionMet) {
originalFn(transport /*, json */);
}
}
Thus you have extended your onSuccess-functions in one central place with just a quick search for onSuccess and pasting in 'wrap(validateResponse)'. This also gives you the option of having several wrapper-functions depending on the needs of the particular Ajax-request.
You can run your method before the other code in onSuccess and return false if something is wrong.
Don't know if this is the cleanest solution, but for me it did the trick.
var tmp = Ajax.Request;
Ajax.Request = function(url, args) {
// stuff to do before the request is sent
var c = Object.clone(args);
c.onSuccess = function(transport){
// stuff to do when request is successful, before the callback
args.onSuccess(transport);
}
var a = new tmp(url, c);
return a;
}
Ajax.Request.protoype = new tmp();
Ajax.Request.Events = tmp.Events;
delete tmp;
"General solution" - independent upon JS framework (kind of)
var oldFunc = Ajax.Request.onSuccess;
Ajax.Request.onSuccess = function foo() {
alert('t');
oldFunc.apply(this, arguments);
}
This will "extend" your JS function making it do exactly what it used to do except show an alert box every time before it executes...

Categories