Javascript - Passing and finding callback functions - javascript

I am writing a small module which will have several different aspects to it, all based around ajax calls. I want to allow the main ajax functions i.e beforeSend, success, complete etc (I am using jQuery) to be customizeable.
What is the best way to do this?
I currently have an options object in the module which can be extended with an options object passed to an init function. In here, I am passing a 'callbacks' object with nested ojects for each different type of action as in...
var insertCallbacks = {
before : function() {
},
success : function() {
},
error : function() {
},
complete : function() {
}
};
var updateCallbacks = {
before : function() {
},
success : function() {
},
error : function() {
},
complete : function() {
}
};
var callbacks = {
insert : addCallbacks,
update : removeCallbacks
};
MY_MODULE.init( {callbacks : callbacks} );
The problem is this then becomes a bit messy, testing for the existence of each of these methods on the ajax callbacks.
Can anyone offer any advice on a good/better pattern for this.

I would go with custom events rather than callbacks. So in your module you will have code like:
MY_MODULE.trigger('updateComplete');
and in all parts outside of module (as well as inside if needed), you bind handlers (now they are callbacks):
MY_MODULE.bind('updateComplete', function() {
alert('update completed');
} );
Custom events in jQuery open doors to complex behaviors, or google any other article. Custom events will help you to keep code structured, and easier to test
ADD ON: with callbacks you need always to check if there is any, so you code becomes
if ( callbacks && callbacks.insert ) {
callbacks.insert();
}
improving your module functionality, and enhancing it, one day you get a situation that few callbacks should be passed for the same situation (e.g. two entities or UI components are interested in module 'updating')... It will make your job too difficult. With events you always have one code line
MY_MODULE.trigger('updateComplete');
with no conditions to check if there is any handler attached (interested in an event), and you can have as many as needed handlers for the same event.

Just do the same thing jQuery does. Let your module fire events (via trigger()) and attach handlers to these events when necessary (via bind()). This way you do not have to check inside your module what functions are listening (or if at all).
Since your code does not contain anything I could use for a sample, it's kind of hard to add code to this answer.

Related

Understanding jQuery & Pub Sub Pattern with this example

I use jQuery for some time, but that is usually very simple jQuery. I just watched some video tutorial in which the author uses something called Pub Sub Pattern. I've never heard of it before, so I have searched on Stackoverflow and Google for explanations:
Why would one use the Publish/Subscribe pattern (in JS/jQuery)?
But it's still not clear to me, especially because of the code that is used by the author of the above mentioned tutorial. So, I will paste this code here and if you can give me explanations:
1. Here is the first .js file named pubsub.js, and I don't understand it:
(function($) {
var o = $({}); // ??? what is this ???
$.subscribe = function() { // ??? and this ???
o.on.apply(o, arguments); // ??? o.on.apply(o, arguments) ???
};
$.unsubscribe = function() { // ??? and this ???
o.off.apply(o, arguments); // ??
};
$.publish = function() { // ??? and this ???
o.trigger.apply(o, arguments); // ?? o.trigger.apply(o, arguments); ??
};
}(jQuery));
I know that with jQuery you can use $( document ).ready() or $(function() but I've never seen (function($) { ... }(jQuery)); - what does this mean/do? Also, I don't understand the rest of the code...
2. The next file is app.js and it contains:
(function() {
$.subscribe('form.submitted', function() {
$('.flash').fadeIn(500).delay(1000).fadeOut(500);
})
});
What does this actually do? Again, what (function() { ... }); means/do? And as for the rest of code, can you explain to me $.subscribe('form.submitted', function() {?
3. Finally, we have something like this:
$.publish('form.submitted', form); // publish?
This also is not clear to me.
I understand that all this is a basic implementation of PubSub Pattern with jQuery, but I still don't get why would someone do in this way (by using this pattern), I have read that answer on Stackoverflow, but it's still unclear to me... I guess that if I understand this code, then it would become clearer to me why and when to use this pattern.
In the case of (function($) { ... }(jQuery));, the author is passing the jQuery instance in as a parameter. Inside the function (which has it's own scope), the $ is a reference to the jQuery instance that was passed in.
"Pub Sub" is just another term for Event Management, or Event Handling. All you're saying is "When [this] happens, do [that]".
When you "subscribe", you are passing in 2 parameters, the "event" that you are listening for, and the code you want to run when the event "fires".
When you "publish", you are "firing" (or triggering) that event.
Think of it like the onclick event. When you set something up on the onclick event, you are subscribing to that event. When you click, you are publishing that event.

Shared JavaScript File with Different Definitions of a Function Call

I have a 300 line javascript file that sets up jQuery event handlers and other needed functions for a partial view that's used by multiple views within a ASP.NET MVC application. The event handlers handle 99% of everything identically regardless of which view is using the partial. This question is about that 1% difference.
Since JavaScript doesn't have interfaces is it safe to define a function to be called by one or more of the event handlers that processes the things that are different in a separate file that is loaded depending on which view is used? If not, what would be the best way to handle this situation? In other languages I'd use interfaces and/or abstract classes in this situation.
Example:
shared file
$(document).ready(function() {
//shared variables here for methods
$(document).on('click', '.selectable-table tbody tr', function() {
//do shared actions
mySpecificFunction();
//finish shared actions (if necessary)
});
});
Definition1.js
function mySpecificFunction() {
//do stuff
}
Definition2.js
function mySpecificFunction() {
//do other stuff
}
The views would load the appropriate scripts as such:
<script src="definitionX.js"></script>
<script src="sharedScript.js"></script>
The "signature" (term being used generously because javascript) of mySpecificFunction() would be the same for each definition, but something in my gut is telling me that this is bad practice. Is there a better/correct way to do this or a design pattern for this purpose?
I think you can use OOP approach here and you don't need the abstract classes or interfaces for that, instead you can use objects (which are more flexible than in other languages).
For example, you can have a base View prototype with shared code and then load specific view1.js, view2.js where the base prototype will be extended with specific code:
$(document).ready(function() {
// view is a view instance coming from the specific view.js
view.init();
});
// sharedScript.js, view prototype
var View = {
init: function() {
$(document).on('click', '.selectable-table tbody tr', function() {
// do shared actions
// ...
// do specific actions
this.mySpecificFunction();
});
},
mySpecificFunction: function() {
//do specific things, can be left empty in the "prototype" object
return;
}
};
// view1.js
var view = Object.create(View);
view.mySpecificFunction = function() {
alert('view 1');
}
// view2.js
var view = Object.create(View);
view.mySpecificFunction = function() {
alert('view 2');
}
And the views would load shared and specific scripts:
<script src="sharedScript.js"></script>
<script src="view1.js"></script>
This is just a rough idea which can be improved, for example, you may want to concatenate and compress all your js code into the single file for production. In this case the global view variable coming from view1.js, view2.js, etc would become a problem.
An improvement can be some kind of "router" which will detect what view should be instantiated:
$(document).ready(function() {
router.when('/', function() {
view = HomePageView();
}).when('/about', function() {
view = AboutPageView();
});
view.init();
});
The approach outlined above will work but it's not the best approach in terms of maintainability. Adding one file or another via a script tag to import the specific function
doesn't necessarily make it clear to another developer that you have actually changed the behaviour of the event handlers in the shared code.
A simple alternative could be that within each view you would wrap the partial view within a containing element that has an identifying css class to differentiate between the behaviour required at that point.
Then assign event handlers individually for those different css classes:
$(document).ready(function() {
//shared variables here for methods
$(document).on('click', 'div.type1 .selectable-table tbody tr', function() {
//do shared actions
mySharedActions();
mySpecificFunction1();
//finish shared actions (if necessary)
});
$(document).on('click', 'div.type2 .selectable-table tbody tr', function() {
//do shared actions
mySharedActions()
mySpecificFunction2();
//finish shared actions (if necessary)
});
});
This would allow you to keep all your specific functions together in one place and makes the changing behaviour predicated by the css class explicit
for future developers to see.

Where does e come from in Jquery and JS?

so i have been programming JS for a while now , and basically i never really understood one thing , I.E. the e in events , have a look at the code below :
have a look at the HTML code :
Hello
Jquery code :
$(function () {
$('a').click(function(e){
console.log(e.target)
})
});
now what is e in the above code , i understand the following :
e is an object normalized by jquery and is being internally passed
also i have come across the following explanation :
The functions you are referring to are called callback functions.
Parameters for those are passed from within the function that is
calling them ( in your case .on() or .click() )
to better illustrate how callback functions work here is an example
function customFunction ( param1, callback ) {
var response = "default response";
if (param1 === "hello") {
response = "greeting";
}
callback(response);
}
customFunction("hello", function(e) {
console.log("this is " + e);
}); // > this is greetings
I have read a famious thread on SO here. , but it only answers what e is and not where it comes from .
BUT I still don't understand where that e is coming from . can somebody explain in a bit of detail ?
Thanks .
Alex-z
When using jQuery the e parameter (which you can rename to anything you like) is going to be an Event object passed to your event handler method by jQuery. The Event object is jQuery's wrapper type for browser event interfaces so that you can have a standard interface in your handlers see here - jQuery.
That type has a property called 'target' which points to the original native browser event interface that jQuery was given by the browser. For example for mouse clicks the native interface would be this for example. Note actual interface may differ across browser implementations particularly older ones which is why jQuery attempts to provide some consistency via their type.

Maintaining Scope

I have a general question about maintaining the scope of this in an object. Here's a simplified snippet of code. Take note of the var that = this line and inside the event handler where I call that.showMenu().
var MyObj = {
init : function(target){
this.$Target = $(target);
this.$Menu = $(target).find('.menu');
this.eventBindings();
},
eventBindings : function(){
var that = this;
this.$Target.on('click', '.anchor', function(e){
e.preventDefault();
that.showMenu();
//some other code
});
},
showMenu : function(){
this.$Menu.show();
}
};
MyObj.init('.myTarget')
Code should be somewhat self explanatory. Typically I try to create reusable methods outside of my eventBindings(). The problem I continually run into is passing through this which would refer to MyObj into the event handler so I can call this.showMenu().
To overcome the obstacle I always assign this to a variable called that so when I'm further down the scope I have a reference. But I feel like this can't be the best method... can someone suggest a better alternative?
What you are doing is the best method. In Javascript this is scoped dynamically (binding depends on stack, that is on the place from where the function was called), all the other variables - are scoped statically (binding depends on static placement of variable in your code).
And since Javascript treats this in a special way, don't feel bad about treating it in a special way too.
You could encapsulate what you are doing now in a function - many libraries provide such a facility, it is usually called "bind". But this will not change what really happens, only hide it (and use up some resources while doing this). Such function could look a bit like:
function whatever (functionToProcess, thisToFreeze) {
return function() {
functionToProcess.apply(thisToFreeze, arguments); // apply is built in
}
}
Further to #Pointy's comment, using Function.prototype.bind:
onClick: function(e){
e.preventDefault();
this.showMenu();
//some other code
},
eventBindings : function(){
this.$Target.on('click', '.anchor', this.onClick.bind(this));
},
You could pass it in as event data:
this.$Target.on('click', '.anchor', {obj:this}, function(e){
e.preventDefault();
e.data.obj.showMenu();
//some other code
});
or store it on the element, but neither are really any different that declaring another variable outside like you are.

In JavaScript is it possible to add to a callback function instead of overwriting it?

I don't know if I'm saying this right, so I'll just ask by explaining with an example.
Let's say I've written a jQuery plugin with an onShowEdit callback.
I later use my plugin and add a bunch of other default functions/methods to the event:
$('.editable_module:not(.custom)').editable({
onShowEdit: function(el){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
}
});
So now I have a basic/default element (.editable_module) that calls the plugin and has some methods/functions that are going to be used in all instances.
My question comes when I have a need to add something to this for a 'one time' kind of deal (I need to add some behavior to this callback/event but not something that is used normally). Is it possible to extend or add to this callback/event without overwriting it? I mean, I know I can go in and do this:
$('#new_selector').editable({
onShowEdit: function(el){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
//ADD SOME NEW STUFF HERE
}
});
But is that really my only option?
Thanks in advance for any input/suggestions.
You could consider jQuery's own event system as follows: http://jsfiddle.net/VQqXM/1/. You can integrate this in your $.fn function pretty easily - just pass the appropriate function as property of the object instead of a function literal.
$("input").on("foo", function() {
alert(1);
});
// later
$("input").on("foo", function() {
alert(2);
});
// later
$("input").trigger("foo"); // alerts 1 and 2
You can simply use .on/.off to bind and unbind events, and trigger them all with .trigger. jQuery also supports namespacing of the event names to make sure you're not using an already used event.
You could use the new $.Callbacks() method
var $onShowEditCBObj = $.Callbacks();
function onShowEditHandler() {
$onShowEditCBObj.fire();
}
$('#new_selector').editable({
onShowEdit: onShowEditHandler
});
// add default event to callbacks obj
$onShowEditCBObj.add(function(){
initRequired();
$(':radio, :checkbox', el).prettyCheckboxes();
initDatePickers();
initChosen();
initMaskedInputs();
$('.dynamic_box.tabs').dynamicBoxTabs();
$('.trigger_dynamic_box').triggerDynamicBox('true');
});
// add a one time method to the callbacks obj
function oneTimeEvent () {
alert("worky");
$onShowEditCBObj.remove(oneTimeEvent);
}
$onShowEditCBObj.add(oneTimeEvent)
With this setup, you can change what callbacks will be fired without having to do anything extra to the editable plugin.
Edit: I didn't realize that you wrote the plugin. With that in mind, pimvdb's answer is more robust than requiring the developer to code a certain way.
If I understand the question correctly, the key word here is "factory".
jQuery is itself a factory but to get what you describe, you need your plugin also to be a factory within the factory. That requires the plugin to be written in a certain way.
Probably the easiest approach is to use jQuery's UI widget factory. Read about it here.
Defining a separate function for onShowEdit should work.
var myOnShowEdit = function(el, extra_fn) {
//standard functionality goes here
if (typeof extra_fn==='function') extra_fn(); //support for extra stuff
}
$('.editable_module:not(.custom)').editable({
onShowEdit: function(el) {
myOnShowEdit(el);
}
});
$('#new_selector').editable({
onShowEdit: function(el) {
myOnShowEdit(el, function(){console.log('hi');});
}
});
This will give you fair flexibility to add whatever functionality you need in addition to the standard stuff. Just be aware of how this may shift contexts.

Categories