Can I get a little advice on my js modules? I'm good with js, but not quite guru status :) Am I refactoring my modules right?
I've been using the js module pattern like this (rough example, I'm just worried about the structure):
sloppy way?
/* Module Code */
var MapModule = (function ($) {
var $_address;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
// do other things
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function () {
loadApi();
}
})(jQuery);
// usage
MapModule.initialize();
But that usage seems a little sloppy. I like constructors.
I refactored some modules like this:
Better way?
(function ($) {
this.MapModule = function () {
var $_address;
var $_mapSelector;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
$_mapContainer = $($_mapSelector);
// do stuff with the jQ object.
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function (selector) {
$_mapSelector = selector;
loadApi();
}
}
})(jQuery);
var map = new MapModule();
map.initialize('#mapcontainer');
That usage seems a lot cleaner to me, and it works just fine, but am I going about it properly?
Taking it another step
Say this module does some stuff with a div that wraps Google Maps and jQuery functionality: Any tips on turning that into a jQ plugin so I can use it with a signature like var map = $('mapcontainer').mapModule();
Thanks!
I have modified your snippet and have actually implemented javascript revealing module pattern which gives the opportunity to implement public & private functions using closure.
Hope this will be helpful:
/* Module Code */
var MapModule = (function (module, $, global) {
var $_address;
var $_mapContainer;
// Public functions
function _loadApi() {
// Do something, maybe load an API?
}
function _someInternalMethod() {
// Do other things.
}
function _initialize = function () {
_loadApi();
}
// Private functions
function _setAddress = function (address) {
$_address = address;
};
function _getAddress = function () {
return $_address;
};
$.extend(module, {
loadApi: _loadApi,
someInternalMethod: _someInternalMethod,
initialize: _initialize
});
return module;
})(MapModule || {},this.jQuery, this);
// Usage
MapModule.initialize();
JSFiddle
Just came across this and thought I'd share my approach...
///////////////////////////////
// Module Code
///////////////////////////////
var ExampleModule = (function()
{
////////////////////////////
// Private Properties
////////////////////////////
var whatever = {
data: 'somedata';
};
////////////////////////////
// Private functions
////////////////////////////
function _init()
{
_loadApi();
_bindToUIEvents();
}
function _loadApi()
{
// load an api
}
function _bindToUIEvents()
{
$('#something').on('click', function(){
// Do something cool
});
}
function _getWhatever()
{
return whatever;
}
//////////////////////
// Public API
//////////////////////
return{
init: _init(),
getWhatever: function()
{
return _getWhatever();
}
};
})();
// Usage
ExampleModule.init;
Related
I have this custom component
(function ($) {
$.fn.stuff = function (options) {
var myStuff = this;
myStuff.render_item = function () {
// Do something
return "default result";
};
myStuff.test = function () {
myStuff.render_item;
};
return myStuff;
};
}(jQuery));
I want to "extend" this component and re-declare the "render_item" fonction without editing the file directly since it's from a library.
How can I achieve this ?
Thank you.
You can monkey-patch it like this:
(function($) {
$.fn.old_stuff = $.fn.stuff;
$.fn.stuff = function(options) {
var myStuff = $(this).old_stuff(options);
myStuff.old_render_item = myStuff.render_item;
myStuff.render_item = function() {
// do something
myStuff.old_render_item();
// do something else
};
return myStuff;
};
}(jQuery));
I have a web page. In my web page I'm referencing some JavaScript I've written in a file called "spacer.js". spacer.js is more complicated, but the general setup is like this:
function spacer() {
// do stuff
console.log(spacer.options);
}
spacer.initialize = function(options) {
spacer.options = options;
};
Then, in my web page, I have:
<script type="text/javascript" src="./spacer.js"></script>
<script type="text/javascript">
spacer.initialize({ id:1 });
window.onresize = spacer();
</script>
When I load my web page, I get an error that says:
Uncaught TypeError: spacer.initialize is not a function.
I don't understand. What am I doing wrong.
function spacer() {
// do stuff
console.log(spacer.options);
}
spacer.initialize = function(options) { // needed an assignment operator and function keyword
spacer.options = options;
}
To create a method you need to use the function keyword.
To the browser, this
spacer.initialize(options) {
spacer.options = options;
}
is interpreted like this
spacer.initialize(options); // method evocation
{spacer.options = options;}; // anonymous object
Change the way it is defined
//from
spacer.initialize(options) {
spacer.options = options;
}
//to
spacer.initialize = function(options) {
spacer.options = options;
}
In your JS remove the () from window.resize call
spacer.initialize({ id:1 });
window.onresize = spacer;
As an aside it looks like you're trying to do one of two things and sitting uncomfortably in the middle. I'd personally go for 1) in this instance, but probably best to stick with one or the other.
1) Creating an object with methods
var spacer = {};
spacer.initialize = function (options) {
this.options = options;
}
spacer.getOptions = function () {
return this.options;
}
spacer.initialize({ name: 'spacer' });
spacer.getOptions(); // { name: spacer });
DEMO
2) Using a constructor function to build an space object instance:
function Spacer() {}
Spacer.prototype.initialize = function (options) {
this.options = options;
return this;
}
Spacer.prototype.getOptions = function () {
return this.options;
}
var spacer = new Spacer().initialize({ name: 'spacer' });
spacer.getOptions(); // { name: 'spacer' }
DEMO
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.
I have couple of modules that do their own thing, but need them to sometimes access a property of one another (not that intertwined, just one json obj). Like so
var Bananas = (function() {
// Bananas.properties would look like this
// Bananas.properties = { 'color' : 'yellow' };
var methodToGetProperties = function() {
API.get('bananas')
.done(function(data) {
Bananas.properties = data;
}
};
var publiclyReturnProperties = function() {
if (!Bananas.properties) {
methodToGetProperties();
} else {
return Bananas.properties;
}
};
var doSomethingBananas = function() {
bananas.doing.something;
bananaHolder.innerHTML = Bananas.properties;
}
var init = function() {
doSomethingBananas
}
return {
init: init,
properties: publiclyReturnProperties,
};
})();
var Apples = (function() {
var doSomethingApples = function() {
apple.innerHTML = Bananas.properties.color;
};
var init = function() {
doSomethingApples();
};
return {
init: init
};
})();
Bananas.init(); Apples.init();
Now, the way I do it now is by simply revealing the methodToGetProperties, which returns the API call, and then work on using jQueries deferred method wherever I call it. But I feel this ruins my code by putting .done everywhere.
I've been reading up to singleton pattern and feel it might be the solution to my problem, but I'm not sure how to implement it. Or maybe implement a callback function in methodToGetProperties, but again not confident as to how.
Would kindly appreciate advice on how to organise my app.
I am learning how to use jsMockito to write perfect code. So, could you give me any idea on how to run callback which is provided to service?
Here is my class:
function MyClass(service) {
this.service = service;
}
MyClass.prototype.doSomething = function() {
this.service.doIt(function() {
console.log("How to run this function while running tests?");
})
}
And here is my test:
var MyClassTest = TestCase("MyClassTest");
MyClassTest.prototype.testMyClass = function() {
this.service = mock(Service);
this.myClass = new MyClass(this.service);
this.myClass.doSomething();
}
So, I need to see the log message:
"How to run this function while running tests?"
Any ideas are welcome.
Finally I have found the solution.
We need to create doItCallback:
function MyClass(service) {
this.service = service;
}
MyClass.prototype.doItCallback = function() {
console.log("How to run this function while running tests?");
}
MyClass.prototype.doSomething = function() {
this.service.doIt(this.doItCallback);
}
Also we need to update the mock:
var MyClassTest = TestCase("MyClassTest");
MyClassTest.prototype.testMyClass = function() {
this.service = mock(Service);
this.myClass = new MyClass(this.service);
var myClass = this.myClass;
when(this.service).doIt().then(function() {
myClass.doItCallback();
});
this.myClass.doSomething();
}