How can I inject Modules in Javascript? - javascript

I'm using Module pattern, now I wanted to know is that possible to inject one module into another like AngularJs.
Below is sample code that I've tried.
module.js
var AnotherModule = (function () {
function AnotherModule() {
this.anotherFunction = function () {
alert('Inside another Module');
}
}
return AnotherModule;
})(window);
var AnotherModule = new AnotherModule();
var Module = (function (window, AnotherModule) {
function Module(AnotherModule) {
var privateMethod = function() {
}
this.getName = function (brand) {
console.log('Inside get Name');
console.log(AnotherModule);
}
}
return Module;
})(window, AnotherModule);
var module = new Module();
module.getName();

Related

Converting code to ES6 modules

I have just started learning es6 module system. I have some es5 javascript code which I want to transform to es6 modules. There are 3 javascript files
workflow-designer.js
var WorkflowDesigner = (function () {
var constructor = function (element, options) {
var component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
extend(Object, constructor, {
getWorkflowName: function () {
return 'WorkflowName001';
},
nextStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
},
prevStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
}
});
return constructor;
})();
(function ($) {
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};
}(jQuery));
extend.js
function extend(parent, child, methods) {
debugger;
let Surrogate = function () {};
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate();
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
for (let name in methods) {
if (methods.hasOwnProperty(name)) {
child.prototype[name] = methods[name];
}
}
// so we can define the constructor inline
return child;
}
There a third file utils.js which contain extension methods like
if (!Array.prototype.find) {
Array.prototype.find = function (predicate) {
//some code here
}
}
if (!Array.prototype.doSomething) {
Array.prototype.doSomething = function (predicate) {
//some code here
}
}
$(document).keyup(function (event) {
//somthing here.
});
I know that to convert the code to es6 modules, I can simply export the extend function like export function extend(.....) in the extend.js file. However, I am not 100% sure how to convert the workflow-designer and utils.js to es6 modules.
I suspect that I need to something like below to convert my workflow-designer.js to es6 module:
export default function workflowDesigner() {
let constructor = function (element, options) {
options = options || {};
let component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
//rest of the code here....
return constructor;
};
Please let me know if I am moving into the right direction or not.
UPDATE:
As per #Bergi's suggesion I changed the extend function like below:
export default function extend(parent, child, methods) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
Object.assign(child, methods);
// so we can define the constructor inline
return child;
}
However, now I am getting error message that "workflowDesigner.getWorkflowName is not a function"
In the debug mode I can see that this function is available at workflowDesigner.__proto__.constructor.getWorkflowName. With the old code it works fine.
Just drop the IIFE from your module pattern - ES6 modules come with their own scope.
import extend from './extend.js';
export default function WorkflowDesigner(element, options) {
if ($(element).hasClass('panel')) {
this.panel = $(element);
} else {
this.panel = $(element).closest('.panel');
}
}
extend(Object, WorkflowDesigner, {
getWorkflowName: () => 'WorkflowName001',
…
});
const $ = jQuery; // you might want to solve this with a proper `import`
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};

AngularJS Unknown Provider Error Message

I have an angular app that will not load and is returning the error message:
Error: [$injector:unpr] Unknown provider: navigatorProvider <-
navigator <- LayoutController
This is ever since I introduced a service I have this registered on the controller, but it still not working. The controller referenced is:
(function () {
"use strict";
angular.module("HtJobPortal").controller("LayoutController",LayoutController);
LayoutController.$inject = ["$scope", "navigator"];
function LayoutController($scope, navigator){
var layout = this;
// Layout
layout.loadTemplate = function() {
return navigator.loadTemplate();
}
// Initialise pending and set roles
layout.init = function () {
// Global Start up
};
layout.init();
}
})();
This is the service:
(function() {
var navigator = angular.module('navigator', []);
navigator.factory('loadTemplate', function () {
var loadTemplate = this;
// Page Directory
navigator.login = "templates/login.html";
navigator.dashboard = "templates/dashboard.html";
navigator.job = "templates/job.html";
// Template switcher
navigator.loadTemplate = function () {
return navigator.login;
}
return loadTemplate;
});
}());
And the app page just in case I've missed something there:
(function () {
'use strict';
angular.module('HtJobPortal', []);
})();
You are add the dependencies when defining the HtJobPortal module
//define dependencies
angular.module('HtJobPortal', ['navigator']);
In the controller, you need to inject the factory in controller
(function () {
"use strict";
angular.module("HtJobPortal").controller("LayoutController",LayoutController);
LayoutController.$inject = ["$scope", "loadTemplate"];
function LayoutController($scope, loadTemplate){
var layout = this;
// Layout
layout.loadTemplate = function() {
return loadTemplate.loadTemplate();
}
// Initialise pending and set roles
layout.init = function () {
// Global Start up
};
layout.init();
}
})();
And define factory as
(function () {
angular.module('navigator', []).factory('loadTemplate', function () {
// Page Directory
var login = "templates/login.html";
var dashboard = "templates/dashboard.html";
var job = "templates/job.html";
return {
// Template switcher
loadTemplate: function () {
return login;
}
};
});
})();
To create a factory\service\controllers , you generally don't require a new module every time. It's preferred to declare one module and register your controller\factory\services to same.
In your case, you can do it like:
(function() {
angular.module('HtJobPortal', [..define other module dependency here..]);
angular.module('HtJobPortal')
.factory('loadTemplate', function () {
var loadTemplate = {};
// Page Directory
loadTemplate.login = "templates/login.html";
loadTemplate.dashboard = "templates/dashboard.html";
loadTemplate.job = "templates/job.html";
// Template switcher
loadTemplate.loadTemplate = function () {
return loadTemplate .login;
}
return loadTemplate; // return object from factory
})
.controller("LayoutController",LayoutController);
LayoutController.$inject = ["$scope", "loadTemplate"]; //inject factory
function LayoutController($scope, loadTemplate){
var layout = this;
// Layout
layout.loadTemplate = function() {
return loadTemplate.loadTemplate(); // call factory method
}
// Initialise pending and set roles
layout.init = function () {
// Global Start up
};
layout.init();
};
}());

A possible structure for a Node module

In my node project I'm using this basic template structure for a single module
(function() {
var SimpleModule;
SimpleModule = (function() {
function SimpleModule(params) {
/** private function */
this.aPrivateFunction = function() {
return "hidden";
};
}
/** public function */
SimpleModule.prototype.foo = function() {
return "bar";
}
return SimpleModule;
})();
module.exports = SimpleModule;
}).call(this);
so that the caller module will do
var SimpleModule
,simpleModuleInstance;
SimpleModule = require('./simplemodule');
simpleModuleInstance = new SimpleModule();
simpleModuleInstance.foo();
Is this a approach formally correct in Node?
How about a simpler approach? Modules are private by default, so everything's already encapsulated except what you export.
function SimpleModule(params) {
/* Not really private!! */
this.aPrivateFunction = function() {
return "hidden";
};
}
/** public function */
SimpleModule.prototype.foo = function() {
return "bar";
}
module.exports = SimpleModule;

Call a function whose name is stored in a variable [duplicate]

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 7 years ago.
I have the following script:
(function () {
var Module = (function () {
var fctToCall = function () {
alert('Foo');
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function () {
var init = function () {
var str = 'fctToCall';
Module.str(); // here
};
return {
init: init
};
})();
})();
So I want to call this fctToCall method by its name - how can I do that? So far I know 3 methods:
by attaching the function to the window object, but then it wouldn't be local and in closure, and I wouldn't have the access to other local variables
eval, the best options as far as I see it, but it's still eval, so I don't wanna use it
this, but it's another architecture, I don't wanna change it
How can I solve this?
To call function use
Module[str]();
As Module is an object, you can access the dynamic properties and methods of it by using the bracket notation.
(function() {
var Module = (function() {
var fctToCall = function() {
console.log('Foo');
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function() {
var init = function() {
var str = 'fctToCall';
// Call as
Module[str]();
};
return {
init: init
};
})();
Module2.init();
})();
Replace:
var init = function () {
var str = 'fctToCall';
Module.str(); // here
};
With:
var init = function () {
var str = 'fctToCall';
Module[str](); // here
};
Here, str is used as key to access the fctToCall function on Module.
Then you can call Module2.init(), in your IIFE:
(function() {
var Module = (function() {
var fctToCall = function() {
document.write('Foo'); // (alert is broken in snippets)
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function() {
var init = function() {
var str = 'fctToCall';
Module[str](); // Access & call `fctToCall`.
};
return {
init: init
};
})();
Module2.init(); // Call `init`.
})();
Since everything in JS is object you can use the object notation.
Module[str]();
You can just invoke the function like this:
Module[str]();

New module inside a module in javascript

Here is my module:
MyModule = (function () {
var myModule = function MyModule(strInput) {
if (false === (this instanceof MyModule)) {
return new MyModule();
}
str = strInput;
}
var str;
myModule.prototype.getStr = function () {
return str;
}
myModule.prototype.test = function () {
var testModule = new MyModule("testInside");
console.log(testModule.getStr());
console.log(str);
}
return myModule;
}());
Here is how I test my module:
document.getElementById("Button").onclick = function () {
var module = new MyModule("input");
module.test();
}
This code returns:
testInside
testInside
to the console.log, but what I expect is:
testInside
input
like I do in c# or java when I build a new class inside the same class.
If you want to keep the str private, you can make it like this:
MyModule = (function () {
var myModule = function MyModule(strInput) {
if (false === (this instanceof MyModule)) {
return new MyModule();
}
var str = strInput;
this.getStr = function () {
return str;
};
this.test = function () {
var testModule = new MyModule("testInside");
console.log(testModule.getStr());
console.log(str);
};
};
return myModule;
}());
In this way the str is in the inner closure, so it's like an instance/object variable in other languages. If you put it in the outer closure it will act like a static/class variable. In both cases, the methods of the myModule object still can access it, but it's not visible from the outside.
str is a variable stored inside the closure that returns MyModule. It is not a property of any object and it is shared between all instances of MyModule.
When you call .test(), you overwrite it.
If you want it to be associated with the object, then put it on the object:
//...
var myModule = function MyModule(strInput) {
// ...
this.str = strInput;
}
//...
myModule.prototype.getStr = function () {
return this.str;
//...
console.log(testModule.getStr());
console.log(this.str);
//...

Categories

Resources