About Revealing module pattern in JavaScript - javascript

I'm currently building a mobile web application with jQM, Highcharts and HTML5.
To maintain the JavaScript code, I decided to apply Revealing module pattern to the code.
Here is my code.
var MobileWebV1 = function () {
function _buildPanelMenu(pageId, isNormalMenu) {
}
function _buildHeaderBar(pageId, isNormalMenu) {
}
return {
buildPanelMenu: _buildPanelMenu,
buildHeaderBar: _buildHeaderBar
};
}();
I'm wondering if I can add another hierarchy to categorize methods in the object.
I want to add 'UserInterface' and 'Util.' In that case, I can call the method like this: MobileWebV1.UserInterface.buildPanelMenu('pageHome', false);
I tried to modify my objecy, but I'm still stuck with the current issue.
If you know the answer, then please share your knowledge.

Just nest the object literals:
return {
Util: {
…
},
UserInterface: {
buildPanelMenu: _buildPanelMenu,
buildHeaderBar: _buildHeaderBar
}
};

Related

Stuck converting ngResource angular service to Vanilla JS

We are migrating our site from old angularjs to using Vuejs.
Step one is to modify our services used throughout the site which all rely heavily on ngResource and convert them into vanilla js code that can be called by Vue.
The challenge is that in addition to making API calls using ngResource they also extending the returning object via prototype.
While using a the module pattern in regular javascript I can mimick the API behaviour of the ngResource service. But I am not clear how to set this up so that it can also support the prototype extensions that are being applied to the returning object (whether a single object or an array).
For example one of our current services might look like this
"use strict";
angular.module("myApp")
.factory("PortfolioService",
[
"$resource", "$rootScope", "$http",
function($resource,
$rootScope,
$http) {
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function() { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl= function() {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
}
]);
Note: that it mames a service call called query but also extends the returning object with a new function called getPicUrl.
I have created a JS equivalent that looks like this
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
var Portfolio = {
query: function() {
return axios.get(baseapipath + "portfolios/");
}
};
Portfolio.prototype.getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
return Portfolio;
})();
The service part works fine but I dont know how to do what ngResource seems to do which is to return a resource from the API which includes the prototype extensions.
Any advice would be appreciated.
Thanks
As I mentioned in my replies to #Igor Moraru, depending on how much of your code base you're replacing, and how much of that existing code base made use of the full capabilities of ngResource, this is not a trivial thing to do. But just focusing on the specific example in your question, you need to understand some vanilla JS a bit more first.
Why does the Portfolio object have a prototype property when it's returned from $resource(), but not when it's created via your object literal? Easy: The object returned by $resource() is a function, which in turn also means it's a class, and those have a prototype property automatically.
In JavaScript, regular functions and classes are the same thing. The only difference is intent. In this case, the function returned by $resource() is intended to be used as a class, and it's easy to replicate certain aspects of that class such as the static query method and the non-static (i.e., on the prototype) getPicUrl method:
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
class Portfolio {
constructor(params) {
Object.assign(this, params);
}
static query() {
return axios.get(baseapipath + "portfolios/").then(res => {
// this convert the objects into an array of Portfolio instances
// you probably want to check if the response is valid before doing this...
return res.data.map(e => new this(e));
});
}
getPicUrl() {
return this.ImgBasePath + this.ImgUrl;
}
}
return Portfolio;
})();
But the problem is, this probably isn't enough. If you're migrating/refactoring an entire application, then you have to be certain of every instance in which your application uses ngResource, and based on your question, I'm fairly certain you've used it more than this class would allow.
For example, every class created by $resource also has static methods such as get, post, etc., as well as corresponding instance methods such as $get, $post, and so on. In addition, the constructor I've provided for the class is just a very lazy stop-gap to allow you to create an instance with arbitrary properties, such as the properties referenced by the getPicUrl method.
So I think you have three options:
Continue playing with the above class to fit something closer to what you need, and then edit every place in your application where your code relies on the Portfolio Service so that it now reflects this new, more limited class. This is probably your best option, especially if your application isn't that big and you don't have to worry about someone else's code not working
Analyze the source code for ngResource, rip it out, and modify it so it doesn't need AngularJS to work. Perhaps someone has already done this and made it available as a library? Kind of a long shot I'd guess, but it may work.
Keep AngularJS in your application, alongside Vue, but only use it to grab the essentials like $http and $resource. An example implementation is below, but this is probably the worst option. There's additional overhead by bootstrapping pieces of angular, and tbh it probably needs to bootstrap other pieces I haven't thought of... but it's neat I guess lol:
const vPortfolioService = (() => {
var inj = angular.injector(["ng", "ngResource"]);
var $http = inj.get("$http"), $resource = inj.get("$resource");
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function () { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl = function () {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
})();
Object instances does not exposes prototype property. Instead you can access it by using:
object.__proto__ // not recommended, or better
Object.getPrototypeOf(object)
Object.getPrototypeOf() return object's prototype object, which you can use to assign new properties.
Object.getPrototypeOf(Portfolio).getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
Note: You still can, though, access the prototype of Function() by doing Function.prototype.
UPDATE: Your Portfolio should be a new object, created from the global javascript object, to avoid the issue that #user3781737 has mentioned.
var Portfolio = Object.create({
query: function() {
return axios.get(baseapipath + "portfolios/");
}
});

Is there a pattern in JavaScript for loosely coupled objects.

I'm relatively new to JavaScript so apologies if this type of question is an obvious one.
We have an app which uses etcd as its way to store data. What I'm trying to do is implement a way of swapping or alternating between different backend data stores (I'm wanting to use dynamodb).
I come from a C# background so if I was to implement this behaviour in an asp.net app I would use interfaces and dependancy injection.
The best solution I can think of is to have a factory which returns a data store object based upon some configuration setting. I know that TypeScript has interfaces but would prefer to stick to vanilla js if possible.
Any help would be appreciated. Thanks.
Interfaces are "merely" a static typing measure to implement polymorphism. Since Javascript doesn't have any static type system, it also doesn't have interfaces. But, it's a highly polymorphic language in itself. So what you want to do is trivial; simply don't write any interfaces as part of the process:
function StorageBackend1() { }
StorageBackend1.prototype.store = function (data) {
// here be dragons
};
function StorageBackend2() { }
StorageBackend2.prototype.store = function (data) {
// here be other dragons
};
function SomeModel(storage) {
this.storage = storage;
this.data = {};
}
SomeModel.prototype.saveData = function () {
this.storage.store(this.data);
};
var m1 = new SomeModel(new StorageBackend1),
m2 = new SomeModel(new StorageBackend2);
m1.saveData();
m2.saveData();
Using TypeScript and actual interfaces gives you the sanity of a statically type checked language with fewer possible surprises at runtime, but you don't need it for polymorphism.
I come from Delphi / C# etc. And interface are just a pain in the but.
Javascript is so much nicer..
With javascript interfaces are not needed, just add the method.
eg.
function MyBackend1() {
this.ver = 'myBackEnd1';
}
function MyBackend2() {
this.ver = 'myBackEnd2';
this.somefunc = function () { console.log('something'); }
}
function run(backend) {
console.log(backend.ver);
//below is like an interface supports
if (backend.somefunc) backend.somefunc();
}
run(new MyBackend2());
//lets now use backend1
run(new MyBackend1());

service vs controller vs external js to put frequently used methods in angularjs

I have an angularjs app, which has several controllers with several viewes. When I started coding the app there were few methods(of similar kind), which were used in more than places, initially it looked OK to me to put those methods where ever needed (two or three controllers). But as my application grew I started noticing the code redundancy issue, as the method was required at more places.
Definitely this was my lack of experience which lead to this issue.
Now I decided to remove this redundant code from my app. I found the following options:
Service way: Remove the redundant code and put it in a new service and include the service all the places where I need the functionality.
External JS: Putting the redundant code in an external js file and just call the required method.
Leave the code as it is.
But here I want to mention that the redundant code I am talking is not very tight coupled and can be added and removed any where with a very little effort.
Now, what I want to know is from the above options, which one should I choose? OR are there much better options available for this issue(may be provided by angularJS itself).
Edit Basic examples of code:as I said
$scope.showSomething = function (show, ele) {
//show or hide the ele (element) based on value of show
}
You are using angular so surely you want to make your app structured according to MVC. what kind of MVC pattern your app will follow if your code is put anywhere in a js file like anything. I would recommend putting your code inside a service. that's the angular way of reducing redundancy. Also you have another option to set the function to the $rootscope here
I'm not sure about your case, but I had similar situation: I had a number of functions which provide validation functionality. I created service:
'use strict';
angular.module('myApp')
.factory('UtilService', ['Env', 'IBANChecker', function(Env, IBANChecker) {
var validateCallbacks = {
checkAddress: function (address) {
return address.action != 'delete';
},
validateIBAN: function (iban) {
return !iban || IBANChecker.isValid(iban);
},
.....
validateYCode: function(id) {
return YCodeChecker.isValid(id);
}
};
return {
/**
* Factory with callbacks for 'validate' directive.
* 0 arguments -- get all callbacks, over wise see #validateCallbacks object to get specific callbacks.
* if wrong callback name requested -> it will be ignored
* #returns {object} -- call requested callbacks.
*/
getValidateCallbacks : function() {
if(arguments.length) {
var result = {};
_.each(arguments, function(argument){
if(validateCallbacks[argument]) {
result[argument] = validateCallbacks[argument];
}
});
return result;
} else {
return validateCallbacks;
}
}
};
}]);
And code in controller looks like:
var validateCallbacks = UtilService.getValidateCallbacks('validateText', 'validateNumber');
_.each(validateCallbacks, function(callback, key) {
$scope[key] = callback;
});
I tend to use factories, specifically because factories can depend on other factories and logical modules can be defined. Consider the psuedo code below.
.controller('HisController', function (UtilityService) {
$scope.foo = UtilityService.foo;
})
.controller('HerController', function (UtilityService) {
$scope.foo = UtilityService.foo;
})
.factory('UtilityService', function (SomeOtherService) {
var service = {
foo: foo,
bar: bar,
}
return service
///////
function foo(a) {
return a.substring(0,1);
}
function bar(a) {
return SomeOtherService.doStuff(service.foo(a));
}
})

Unclear javascript/jquery programming pattern

I am working on a web project where in the UI jsp pages. All the jquery/javascript methods are called via this pattern
A.b.c.d.methodName()
There are many .js files imported in the jsp page. So I have to search in Eclipse IDE
to track the method js file.
In the js file which has an entirely different name not "A.b.c.d", the method is declared as
methodName: function()
{ // logic }
Can anyone tell me what is this style/pattern of using jquery.
JavaScript never looks for file names, the "namespacing" you see there is achieved by objects nested in each other as properties.
For example if you create an object like:
var A = {
b: {
c: {
d: {
methodName: function () {
console.log('What a nice method!');
}
}
}
}
};
You can call it like this:
A.b.c.d.methodName();
Or you can add methods later in your code:
var irrelevantName = function () {
console.log('This method is even nicer');
};
A.b.c.method2 = irrelevantName;
And call it by:
A.b.c.method2();
There is a much used extend method which has surfaced in lot of JavaScript frameworks, like jQuery or MooTools. This provides a way for safely extending an object while preserving original values if present.
You can use the jQuery one like:
$.extend(A.b.c.d, {
method3: function () {
console.log('An other nice method');
}
});
And as you expect, it can be called as:
A.b.c.d.method3();
JavaScript libraries usually use namespacing: they create some kind of an object and populate it with all their methods. This way they don't pollute the global namespace with their methods.
There are a lot of ways to add new properties to an object in JS, so it is not always obvious how a method is added to an object, but it is safe to say that file names have nothing to do with it.
For further reading on the subject, I would recommend this google search. Basically any of the top 20 results should explain how namespaces are created and used in JavaScript.
On a footnote: I'm not sure how does the Eclipse tooling support JS, but as it is not a trivial problem (object structure can be modified on the fly) I would not be surprised if Eclipse had no understanding of JavaScript namespacing.
Looks like it has some sort of namespacing. The code could be using could be the AMD pattern? But again, if it's JSP it might be old....

Problems with circular dependency and OOP in AngularJS

AngularJS + OOP is kinda sexy feature to use
Hi, I'm successfully using OOP with AngularJs for some time already (first started with angularjs with oop inheritance in action), the provided approach allows you define your classes as angular services, which you can later extend or inherit from like that:
Application.factory('AbstractObject', [function () {
var AbstractObject = Class.extend({
virtualMethod: function() {
alert("Hello world");
},
abstractMethod: function() { // You may omit abstract definitions, but they make your interface more readable
throw new Error("Pure abstract call");
}
});
return AbstractObject; // You return class definition instead of it's instance
}]);
Application.factory('DerivedObject', ['AbstractObject', function (AbstractObject) {
var DerivedObject = AbstractObject.extend({
virtualMethod: function() { // Shows two alerts: `Hey!` and `Hello world`
alert("Hey!");
this._super();
},
abstractMethod: function() {
alert("Now I'm not abstract");
}
});
return DerivedObject;
}]);
Plunker: http://plnkr.co/edit/rAtVGAsNYggBhNADMeoT
using the described approach gives you the ability to define classes that beautifully integrate into angular infrastructure. You get all sort of nifty features from two worlds - OOP and AngularJs. Dependency injection is free for your classes, and it makes your classes simple, allows putting a lot of boilerplate controller code into some base class that can be later reused.
However
AngularJs infrastructure blocks previously described approach from spreading it's wings on all 100%. The problem occurs when you try to define recursive class definitions (i.e. recursive aggregation), say you have two class definitions like Blog and Tag
Application.factory('Blog', ['Tag', function (Tag) {
var Blog = Class.extend({
tags: function() {
return this.tags;
}
});
return Blog;
}]);
Application.factory('Tag', ['Blog', function (Blog) {
var Tag = Class.extend({
Blogs: function() {
return this.blogs;
}
});
return Tag;
}]);
It won't work because both Blog and Tag are self-referencing themselves causing circular dependency.
P.S
The last thing, I have found kinda ugly solution that solves my problem in my specific case but doesn't work in general and as I said, it isn't pretty:
Application.factory('BlogNamespace', [function () {
var Blog = Class.extend({
tags: function() {
return this.tags;
}
});
var Tag = Class.extend({
Blogs: function() {
return this.blogs;
}
});
return {
Tag: Tag,
Blog: Blog
};
}]);
Question
The above fix won't work because namespaces may also be a subject of circular dependency. This means that it isn't solution to described problem but rather one level deeper problem now.
Any suggestions on how it is possible to solve described problem in general case?
A circular dependency is always the sign of mixing of concerns, which is a really bad thing. Miško Hevery, one of the authors of AngularJS, explains a nice solution on his awesome blog. In short, you probably have a third service hidden somewhere, which is the only part of your code really needed by the two others.
I'm answering my own question just because I've found a technical way of resolving the issue that I have originally posted about. But before that, I strongly encourage you to use Blackhole's suggestion since it allows solving a broader set of problems which are usually caused by bad architecture. Please prefer using his approach first, and return to current one in case that you know what you are doing.
So here goes:
You can use $injector service and inject required definitions at run-time, which is legal from technical point of view, but again according to this post (hard to imagine that it is written in 2008), this is like a black magic, do that and it will strike you back:
Application.factory('Blog', ['$injector', function ($injector) {
var Tag = $injector.get('Tag'); // Here is your tag
...
}]);
Application.factory('Tag', ['Blog', function (Blog) {
...
}]);
Edit
It turned out that current approach is an example of Service Locator pattern, which is IoC Antipattern.
LAST RESORT: NOT ENCOURAGED
In my case the best way to get around a circular-dependency-problem like this in angular, is to trigger function-calls via $rootScope-broadcasts. The other service can then listen to this broadcast and react with the desired function-call. It may not be the most elegant solution but in some cases where the interaction between the services is mainly one-directional anyways, it may be a reasonable alternative. (note that this also allows return-values to be passed back to the broadcasting function via callbacks only)
A pseudo-example of this would be:
angular.module('myApp').factory('service1', ["$rootScope",
function($rootScope) {
function func1() {
// do something
}
$rootScope.$broadcast("callFunc2"); // calls func2 from service 1
return {
func1: func1
}
}
]);
angular.module('myApp').factory('service2', ["service1", "$rootScope",
function(service1, $rootScope) {
function func2() {
// do something
}
service1.func1(); // calls func1 from service 2
$rootScope.on("callFunc2", func2);
}
]);

Categories

Resources