Dependency injection in javascript - javascript

I have been playing around with dependency injection with javscript but have some questions that I need help with
A simple example is a dialog module I have, used in multiple places on the page it alerts a user with a custom message when a user interacts with a component on the page
function Dialog () {
}
Dialog.prototype.show = function () {
}
and this may be used in a component, say a search control which validates a user search and if its empty it fires an error dialog. With dependency injection I'm assuming I would write:
function searchComponent (dialog) {
this.dialog = dialog
}
searchComponent.prototype.validateSearch = function () {
// validate search if invalid create error
this.dialog.show();
}
var searchDialog = new Dialog();
var search = new searchComponent(searchDialog);
However a user may never need the search error dialog, yet I am creating an instance of it just so that I can then pass the dependency through, what if I have 100 individual instances of a dialog on the page do I construct these 100 times, this is unnecessary and expensive in performance.
what I would rather do is lazy load the construction of a dialog to a time when it is needed
searchComponent.prototype.validateSearch = function () {
//validate search if invalid create error
var dialog = new Dialog();
dialog.show();
}
now I know that this creates disadvantages and one of these is the affects it has on unit testing, what I am keen to understand is whether I have missed something or an alternative method?
Thanks in advance

JavaScript functions are first class objects. Instead of passing in a constructed dialog, pass in the dialog constructor function:
var search = new SearchComponent(Dialog);
Then new it up when you need it:
function SearchComponent(Dialog) {
this.Dialog = Dialog;
}
SearchComponent.prototype.validateSearch = function() {
var dialog = new this.Dialog();
dialog.show();
}

To extend #ChrisTavares' great solution, you can use something like this to make dependency injection inside the Dialog possible as well:
var foo = function () { return new Foo() }; // just an example
var search = new SearchComponent(function() {
return new Dialog(foo());
});
Inside your SearchComponent:
function SearchComponent(Dialog) {
this.Dialog = Dialog;
}
SearchComponent.prototype.validateSearch = function () {
var dialog = new this.Dialog();
dialog.show();
};

Inspired by the previous examples, I've created a simple jsFiddle that utilizes a small library called Syringe.js in order to show how dependencies can be injected by pre-binding the SearchComponent constructor.
When a SearchComponent object is created, the validator dependency (a separate component, here taking the place of an actual dialog) is automatically provisioned. This dependency is subsequently used by the validateSearch method.
The advantage of doing it this way is that you don't have to have any dependencies in your hand when you create each SearchComponent object instance.
In addition, the validator dependency can be modified after theSearchComponent objects are created, and the behavior of the dependent control(s) can be updated accordingly.

I recently wrote a dependency injection library called infect.js. Check it out, might just be what you're looking for. https://github.com/amwmedia/infect.js

Related

JavaScript OOP and Reflection - Are there any (non-trivial/ugly hack) ways to call a 'private' method from outside a class itself?

Are there any (non-trivial/ugly hack) ways to call a 'private' method from outside a class/module itself?
Please don't ask why I need this.
Just my personal curiosity and trust in power of doing anything in JS :)
function Module () {
var privateMethod = function () {
alert('1');
};
var publicMethod = function () {
privateMethod();
alert(2);
};
return {
pm: publicMethod
};
}
var m = new Module();
m.pm(); // can i call m.privateMethod() here somehow?
DON'T TRY THIS AT HOME
So you've been warned, now look at this (fiddle; I've replaced all the alerts with console.log() for the greater good):
var methodName = 'privateMethod';
var mSource = Module.toString();
var methodPattern = new RegExp(methodName + '\\s*=\\s*function[^]*?\\{([^]+?)\\};');
var privateMethodSource = mSource.match(methodPattern);
var privateMethodRebuilt = new Function([], privateMethodSource[1]);
privateMethodRebuilt();
It's one possible way to do this with HUGE number of restrictions. First, this particular snippet doesn't even try to parse the arguments, assuming that the method in question doesn't need any. Second, you won't be able to access the other private variables defined within the Module (as the code rebuilds only the particular function, not the environment).
Surely, you can take it further - and rebuild the Module itself, making the target method public (for example, by adding the private function into the exposed methods' list). The question is, WHY on Earth do you even think about needing such thing as using the private method outside the module?

Implementing Singleton pattern with IIFE in JavaScript

Employees that previously worked at my company used the following form of the Singleton pattern to create and obtain UI components in JavaScript:
getDetailForm: function() {
this.getDetailForm = (function() {
var form = // form creation logic
return function() {
return form;
};
}());
return this.getDetailForm();
}
Is there any reason to use that variation over the following standard way?
getDetailForm: function() {
var form;
if (!form) {
form = // form creation logic
}
return form;
}
The second code block will not remember the value of the variable form: every time the function getDetailForm is called, it represents a new closure, and a new variable form is created within that scope, which will start out as undefined -- each time.
See how the following prints "init" on each call:
var o = {
getDetailForm: function() {
var form;
if (!form) {
form = 'form'; // form creation logic
console.log('init');
}
return form;
}
}
console.log(o.getDetailForm());
console.log(o.getDetailForm());
You can make it work by declaring form in the scope of your singleton object, and for that you could use a constructor for instantiating that object, which at the same time is a closure for your form variable:
var o = new function () {
var form;
this.getDetailForm = function() {
if (!form) {
form = 'form'; // form creation logic
console.log('init');
}
return form;
}
};
console.log(o.getDetailForm());
console.log(o.getDetailForm());
See how the output now only shows "init" once.
The difference
The first version you provided has a tiny advantage: after the first call the function will have been replaced by a very basic function:
function() {
return form;
};
There is not even an if in that function. It is only a return. One could argue that therefore it is to be preferred: no performance is lost by the evaluation of an if condition on any subsequent calls of this function, which, when you call the method many times, always returns the same result, except for the first time.
However, also that can be achieved with the constructor pattern, if you would assign the value to form directly in the constructor function. Then you don't need the if in the method any more, as the initialisation already took place in the constructor.
Note that this is not exactly the same, because now the constructor is doing the heavy lifting of assigning the (maybe very time consuming) expression to form. The advantage of the first code you provided, is that this is only done when the function is called the first time, which you could consider an advantage: "don't waste time on things that might never be used".

Adding code to a javascript module pattern from an outside file

First of all I'm pretty new to javascript.
I have wrote a javascript plug-in that filters html records. Using Knockout.js, basically keyword/s are typed into a text box and the plug-in filters through the html records to reveal the records that contain the keyword/s.
I have wrote the javascript using the Module pattern, and would like the opportunity for the .js file to stand alone, whilst also giving the user the opportunity to change ways in which the filter works.
Here is a brief and simple overview of the structure of my .js file:
$(function(){
var s,
Filter = {
settings:{
//default settings
},
initialise: function(){
s = this.settings;
this.someFunction1;
this.someFunction2;
},
someFunction1: function(){
//
},
someFunction2: function(){
//
},
}
Filter.initialise();
});
As you can see, I have specified one function to be called - initialise. Within initialise I have set the variable s (declared at the same level as the module) to point to settings so that all sub functions of the module can access it.
What I want to know is, is it possible for the overriding settings to be passed via the html file that calls the .js file?
Ideally I would like there to be default settings for the plug-in, but give the user the option to specify/override certain settings unique to their need.
Any help would be appreciated. Thanks.
First up, there's a few peculiarities in your code.
One thing is that you have this.someFunction1; (and one for the second function) in your initialize function, but that doesn't quite do anything. It's just a statement.
Another thing is that you declare Filter as an object, but you're missing , (commas) between the various properties.
Finally, you declare someFunction2 twice (though I assume it's an copy/paste error?), and you're missing a semi-colon.
To find these problems you can use a JavaScript linting tool, for example JSHint. Try copy-pasting your question's code there and you'll see all those issues pop up.
If I fix those issues I get to this:
$(function(){
var s,
Filter = {
settings:{
//default settings
},
initialise: function(){
s = this.settings;
},
someFunction1: function(){
//
},
someFunction2: function(){
//
}
};
Filter.initialise();
});
Currently in this code, the Filter is only visible in the outer closure. To make it available to other bits of code you'll have to export it, either to your own namespace object or as a jQuery plugin.
The first option is possible, but will require a bit more work and assumptions about your setup. So let me stick to showing the second option. The jQuery's plugin tutorial is pretty good, but I've based the following code on this blogpost because it's a bit more complete IMO:
(function($) {
$.filter = function(element, options) {
var defaults = {
// default settings
}
var filter = this;
filter.settings = {};
var initialise = function() {
filter.settings = $.extend({}, defaults, options);
filter.element = element;
// code goes here
}
// This function is *public*, just save it in a 'var' instead of setting it
// as a property of 'plugin' to keep it private to your plugin.
filter.someFunction1 = function() {
//
}
filter.someFunction2 = function() {
//
}
initialise();
}
})(jQuery);
In this code the jQuery extend function is used above to extend default settings with user provided options.
You can call your plugin in its most basic form like this:
var options = { filterEmptyOptions: true, showTimeZone: false, /* etc */ };
$.filter($('#myDiv'), options);
Additionally you could save the result of last line and call the plugin's public methods later on.

AngularJS controller and methods

I'm a beginner in angularjs with a few questions about controllers.
Here's my example controller:
function exampleController($scope)
{
$scope.sampleArray = new Array();
$scope.firstMethod = function()
{
//initialize the sampleArray
};
$scope.secondMethod = function()
{
this.firstMethod();
};
};
Here are my questions:
How I can call firstMethod from secondMethod? Is the way I did it correct, or is better way?
How I can create a constructor for the controller? I need to call the secondMethod that call the firstMethod that initialize the sampleArray?
How I can call a specific method from html code? I found ng-initialize but I can't figure out how to use it.
You call a method the same way you declared it:
$scope.secondMethod = function() {
$scope.firstMethod();
};
Which you can also call from HTML like so:
<span>{{secondMethod()}}</span>
But controllers don't really have "constructors" - they're typically used just like functions. But you can place initialization in your controller function and it will be executed initially, like a constructor:
function exampleController($scope) {
$scope.firstMethod = function() {
//initialize the sampleArray
};
$scope.secondMethod = function() {
$scope.firstMethod();
};
$scope.firstMethod();
}
you call the first method by using $scope.
So
$scope.secondMethod = function()
{
$scope.firstMethod();
};
Not really sure what you mean in your second question.
For your third quesiton, you can either have the method run automatically "onload" on controller, OR run it via an front-end angular binding.
e.g.
Run Automatically
function exampleController($scope)
{
$scope.sampleArray = new Array();
$scope.firstMethod = function()
{
//initialize the sampleArray
};
$scope.secondMethod = function()
{
$scope.firstMethod();
};
$scope.secondMethod(); // runs automatically.
};
Run on binding
<div ng-controller="ExampleController"> <!-- example controller set up in namespace -->
<button class="btn" ng-click="secondMethod()">Run Second Method</button>
</div>
#Josh and #Christopher already covered your questions, so I won't repeat that.
I found ng-initialize but I can't know how to use that :-(
The directive is actually ng-init. Sometimes (e.g., if you are starting to use Angular in parts of an application and you still need to dynamically generate a view/HTML page server-side), ng-init can sometimes a useful way to initialize something. E.g.,
<div ng-controller="ExampleCtrl">
<form name="myForm">
<input type="text" ng-model="folder" ng-init="folder='Bob'">
Here's an example where someone needed to use ng-init: rails + angularjs loading values into textfields on edit
I'd also like to mention that controllers are not singletons. If you use ng-view, each time you go to a different route, a new controller is created. The controller associated with the view you are leaving is destroyed, and the controller associated with the view you are going to is executed. So that "initialization code" in a controller could get executed multiple times while an app is running. E.g, if you visit a page, go elsewhere, then come back, the same controller function (and its "initialization code") would be executed twice.
If you want something to truly run once, put it in a service or in a module's config() or run() methods. (Services are singletons, and hence each service is instantiated only once, so initialization code in a service is only run once.)

Creating a jquery dialog as an API

In my current application I am using jquery UI dialog at many places , so I am planning to create a method like
var MYAPP = MYAPP || {};
MYAPP.overlay = (function(){
$("#id").dialog();
}());
This is my idea but now the problem is my overlay is used for different purpose like overlay form, video, confirmation message etc. Is there a way I can have all the option inside my API . so I just have to call MYAPP.overlay("video",some other parameter) and it will create the overlay without have to repeat the code again and again....any idea or suggestion will be appreciated..
I'm not sure what you are trying to accomplish with the immediately executing anonymous function, but you can do something like this:
MYAPP.overlay = function MYAPP$overlay(id, paramsObj) {
// do something based on element type, id, or params obj here.
$(id).dialog();
// possibly return something if needed.
};
yes you can use parameters. here is a very generic way of doing it:
MYAPP.overlay = (function(){
// complex code ....
return function(arg) {
alert(arg);
}
})();
// example
MYAPP.overlay('hello');
will alert hello

Categories

Resources