combine multiple functions with same code in jquery - javascript

Yes, I have thoroughly searched google and did not find anything that suits my requirement.
The code i have so far is at the link below:
http://jsfiddle.net/ZKwTY/4/
There are multiple onchange events which call almost the same code, i would like to combine them maybe in a comma separated fashion to call it only once.
something like this
(on1Change, on2Change, on3Change): function () {
this.loadData();
}
is this possible??
Note: these functions are bound to the controls via a framework over which i do not have control, i need to create these functions and the framework would bind these to the respective controls

or you can create your object like this
var ol = {
on1Change: this.loadData,
on2Change: this.loadData,
on3Change: this.loadData,
on4Change: this.loadData,
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
};
Then if you want to do it once, then declare a object
var ol = {
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
};// end of object
ol.on1Change = ol.on2Change = ol.on3Change = ol.on4Change = ol.loadData;
add all propteries dynamically after object declaration

use bind()
$("selector").bind(on1Change, on2Change, on3Change): function () {
this.loadData();
}.....

you can try somethig like this http://jsfiddle.net/s4VVY/
i.e. add methods after object create
[1,2,3,4,5].forEach(function(it){ol["on"+it+"Change"] = function(){this.loadData()}})
UPDATE
may be this help
var ol = (function(){
var o = {
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
}
o.on1Change=o.on2Change=o.on3Change=o.on4Change=function(){ this.loadData();};
return o;
})()
also you can make function bindFunc
function bindFunc(){
var obj = arguments[0],
handler = arguments[1],
properties = Array.prototype.slice.call(arguments,2);
for(var i in properties){
obj[properties[i]] = handler;
}
}
and call as
bindFunc(o,function(){this.loadData();},"on1Change","on2Change","on3Change","on4Change")

Related

break large public javascript functions into smaller private functions

I have JavaScript class which have huge functions which are very difficult to maintain.
The 2 public functions are called at start and then on click. I want to create private functions inside these public functions say break into into some private functions scope to these public methods.
var searchResultView;
var SearchResultView = function () {
me = this;
this.init = function () {
// huge code
}
this.Search = function () {
// huge code
}
}
jQuery(function () {
searchResultView = new SearchResultView();
searchResultView.init();
searchResultView.Search();
}
What will best way to achieve this. I tried to use below approach but i think this nested function will not work well.
var searchResultView;
function searchResultView() {
me = this;
this.init = function () {
var declareControls = function () {}
var addEvents = function () {}
var fillControls = function () {}
declareControls();
addEvents();
fillControls();
}
this.Search = function () {
var validateAndCreateCriteria = function () {
if (!validateAandGetLocation()) {
alert("invalid location");
return false;
}
if (!validateAandGetCategory()) {
alert("choose search type");
return false;
}
var validateAandGetLocation = function () {}
var validateAandGetCategory = function () {}
}
validateAndCreateCriteria();
}
}
jQuery(function () {
searchResultView = new searchResultView();
searchResultView.init();
});
If I understood correctly, you should have the functions something like this:
var foo = (function() {
var privateBar = function() { // private function
},
privatefooBar = function() { // private function
};
return {
publicFoo : function() { //public function
/* use privateBar and privatefooBar functions here */
}
};
})();
Later you can access publicFoo function by using
foo.publicFoo();
But you can't access the inside functions which are privateBar() and privatefooBar() directly because they are private functions.
Updated Fiddle
Breaking up the function is easy:
function f(..) {
// many lines here
return ret_f;
}
if equivalent to
function f {
function f1(..) {
// not so many lines here
}
function f2(..) {
// not so many lines here
}
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
or if you prefer this style using anonymous functions
function f {
var f1 = function(..) {
// not so many lines here
};
var f2 = function(..) {
// not so many lines here
};
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
I fear however your real question is specific to your existing code and is about what useful smaller functions to extract there and how to combine them.
For this one would need to have your full code and understand it. That might be a bit much for this QA format.

function expression with namespace

Actually I am trying to have a namspace [to avoid global variables] without object creation and trying to do the below. But, the execution of the methods data.sum and data.calc.mult with alerts is not getting called. Instead the empty declarations inside data are called. Can I anyone help me know why this is happening?
var data = {
name: "",
sum: function() {},
calc : {
mult: function() {}
}
};
data.sum();
data.calc.mult();
data.sum = function () {
alert('sum');
};
data.calc.mult = function () {
alert('mult');
};
If you put your data.sum() after data.sum function redefinition, you will get the alert box.
Define it like this (function definition within object definition):
var data = {
sum: function () {
alert('sum');
},
mult: function () {
alert('mult');
}
};
data.sum();
data.mult();

jQuery off not working as I expected

Resolved!! see the end of the question for the result that I used
I am trying to write a function that can handle my apps paging by routes.
I have a function route() that is called with argument being the route(page) to move to.
route is an object that defines a model that it uses that handles its logic.
This model contains 3 functions
indexAction
- This renders my view and appends it to my page.
bindEvents
- This is where I have placed all of my click events
shutDown
- This is instructions to run when moving to a new page
The router function first runs shutdown on the current page, here I have the $(selector).off() and $(selector).remove()
it then runs the enidexAction and bindEvents function.
My issue now is when I return to this page, all my click functions are running twice, then three times etc... its as if the off() never actually unbind from the anchor.
here is an example of one of my models
var NewPageModel = (function() {
var instance;
var modal = 'null';
function createInstance() {
var object = {
indexAction: indexAction,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function indexAction (data, callback){
var partials = {};
ViewManager.render('pageName',{context:data}, partials,function(html){
ViewManager.appendUnique('#xxx',html,'uniqueID');
callback();
});
}
/**
* Remove modal
*/
function shutDown(){
this.modal.off();
this.modal.remove();
}
function bindEvents() {
if(this.modal!='null'){
return;
}
this.modal = $(PagerManager.pages.newGroup.id);
this.modal.on('click','div.close', function () {
shutDown();
});
this.modal.on('click', 'button.cancel', function () {
shutDown();
});
this.modal.on('click', 'button.submit', function () {
//code that submits form information
});
}
return {
getInstance: function () {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
EDIT!!
So I am still learning about the importance of scopes and how they can be applied to functions
Here is the working code
var NewPageModel = (function() {
var instance;
var modal;
function createInstance() {
var object = {
indexAction: indexAction,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function indexAction (data, callback){
var partials = {};
ViewManager.render('pageName',{context:data}, partials,function(html){
ViewManager.appendUnique('#xxx',html,'uniqueID');
callback();
});
}
/**
* Remove modal
*/
function shutDown(){
this.modal.off();
this.modal.remove();
this.modal = null;
}
function bindEvents() {
//This is confused logic, if I use off() in shutdown, I don't need to do this as I need to bind all the events again. hence in shutdown modal=null;
if(!this.modal){
return;
}
this.modal = $('#modal');
this.modal.on('click','div.close', function () {
shutDown().apply(this);
}).bind(this);;
this.modal.on('click', 'button.cancel', function () {
shutDown().apply(this);
}).bind(this);;
this.modal.on('click', 'button.submit', function () {
//here I only use the apply(this) if I use another internal function
//code that submits form information
}).bind(this);;
}
return {
getInstance: function () {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
You are losing your this in the event handler functions (this will be the element clicked) so the shutDown is not getting the correct this:
this.modal.on('click','div.close', function () {
shutDown();
});
should be:
var self = this;
this.modal.on('click', 'button.cancel', function () {
self.shutDown();
});
e.g.
function bindEvents() {
var self = this;
if(this.modal!='null'){ /// <<<< !!!!!! WTF
return;
}
this.modal = $(PagerManager.pages.newGroup.id);
this.modal.on('click','div.close', function () {
self.shutDown();
});
this.modal.on('click', 'button.cancel', function () {
self.shutDown();
});
this.modal.on('click', 'button.submit', function () {
//code that submits form information
});
}
Note: I am ignoring the string comparison to null for now as I have no clue what you are doing there :)
As pointed out in comment by #Gurami Dagundaridze you can also retain the correct this using bind (I think the syntax goes like this):
this.modal.on('click', 'button.cancel', shutDown.bind(this));
In the spirit of keeping your syntax and just fixing the bug,
if(this.modal!='null'){ should be if(modal!='null'){
Because this.modal will be undefined at that condition and will just return.
In the spirit of fixing your code, you need to keep a reference to this or it will default to window in the browser.
var modal;
function createInstance() {
var object = {
modal : modal,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function bindEvents() {
if(this.modal){
return;
}
// ..... //
this.modal.on('click','div.close', function () {
shutDown.apply(this);
}.bind(this));
// ..... //
}
Working demo :
http://jsfiddle.net/uyovgdj3/

Expose knockout ViewMode from function to another function

I have next situation...
For some reasons I need to bind knockout ViewModel inside function and call it on specific terms.
this is my code:
if (... some conditions ...) {
var polugodiste = $("#polugodiste").val();
ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});
}
and function:
function ApplyBindingsIzostanak(polugodiste)
{
var Izostanak = function (cas, tekst) {
this.Cas = cas;
this.Tekst = tekst;
};
var IzostanakViewModel = {
selectedStatus: ko.observable(),
selectedPolugodiste: ko.observable(polugodiste),
ucenikIzostanakList: ko.observableArray([]),
GetIzostanci: function () {
.. do some code ...
}
};
ko.applyBindings(IzostanakViewModel);
}
Binding is working, but I get error when I try calling IzostanakViewModel inside my if, it says IzostanakViewModel is not defined.
Can I and how expose IzostanakViewModel from function and use it inside if statement?
NOTE*
I could try something like this:
add this code to ApplyBindingsIzostanak():
window.foo = function() {
IzostanakViewMode.GetIzostanci();
}
and then call it from if statement, but maybe there is better solution...
IzostanakViewModel is a variable within the ApplyBindingsIzostanak() function. Why don't you just return it so you have a reference to it?
function ApplyBindingsIzostanak(polugodiste)
// ...
return IzostanakViewModel;
}
var IzostanakViewModel = ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});

Invoke public function from internal/private function?

Just wondering if I'm missing something or not but I attempted to do the following:
(function() {
var thing = function() {
var doIt = function() {
console.log("just do it");
this.updateValue(5);
};
return {
updateValue: function(val) {
console.log('updating value: ' + val);
},
go: function() {
doIt();
}
}
};
var t = thing();
t.go();
}())
This results in "just do it" showing up in the console followed by an error b/c it says "updateValue" is not a function.
I was wondering, can an internal/private function (e.g. "doIt") invoke a public function (e.g. "updateValue")? Perhaps this is just bad design and you should never really want to do this and I've actually refactored my code to avoid/not do this but I was curious if it was possible.
Thanks in advance.
Either use call/apply to explicitly specify the context for this (like #SLaks and #Alnitak) mentioned or else define the function at the beginning and then add it as a property to the returned object:
var thing = function() {
var updateValue = function () { /* */ },
doIt = function() {
console.log("just do it");
updateValue(5);
};
return {
updateValue: updateValue, // minor duplication here
go: function() {
doIt();
}
};
};
If the minor duplication annoys you, you can also do this:
var thing = function() {
var exposed = {
updateValue: function(val) {
console.log('updating value: ' + val);
},
go: function() {
doIt();
}
}, doIt = function() {
console.log("just do it");
exposed.updateValue(5);
};
return exposed;
};
Writing doIt(), calls the function in the global context, so this is the window object.
You need to write doIt.call(this) to pass your this as the context for doIt.
Per #SLaks answer, this is incorrect when invoked by doIt().
Instead, try:
doIt.call(this);

Categories