Traditionally I have managed my Angular code like this
//File 1
angular.module('name',[])
//File 2
function TestController(){
}
TestController.prototype.// inherited stuff
angular.module('name').controller('testController',TestController);
This worked great and allowed me to partition my files easily. Now I try to upgrade to 1.3 and get the infamous...
Error: [ng:areq] Argument 'TestController' is not a function, got undefined
Of course this is due to this change which claims a desire to clean up the way people write code. What about this pattern is more complex? Is there a way to maintain this pattern without changing the global settings?
There is actually a comment on the page you linked to that had a fairly solid explanation.
Global controllers refer to your controllers being defined as function
on the window object. This means that they are openly available to
conflict with any other bit of JavaScript that happens to define a
function with the same name. Admittedly, if you post-fix your
controllers with ...Controller then this could well not happen but
there is always the chance, especially if you were to use a number of
3rd party libraries. It is much safer to put these controller
functions inside the safety of a module. You then have more control
over when and where this module gets loaded. Unfortunately controller
names are global across an individual Angular app and so you still
have the potential for conflict but at least you can't clash with
completely different code in the JavaScript global namespace.
So the idea is that global controller functions could conflict with any other global function in any javascript you use. So to eliminate the chance of a conflict with your own code or a third-party script, not using global controllers makes your code safer and more consistent.
As mentioned in the comments by #Brett, you can use IIFE around your prototyping. Here is an update of your plunk that uses that. The main change just looks like this.
(function() {
TestController.prototype.name = 'World'
})();
What comes to my mind is 2 things:
1) in that way functions wont be kept in memory more than they should.
2) if you minify your code, minifyer will have to generate new names for all global objects, which is sfine when you have small project, but will be a problem when it's not.
Also it should prevent tests to modify unnecessary data.
Related
(function (angular) {
"use strict";
angular.module('module')
.filter('leFilter', function() { ... });
})(angular);
Saw this code in a new project I'm working on.
I usually just begin the module at the root of the file and dont use 'strict' mode.
angular.module('module')
.filter('leFilter', function() { ... });
I've never ran into a single issue doing this.
In the context of an angular application, is there really anything to gain from the self-executing function and 'strict' mode?
I really don't see any major benefit from running it in an IIFE(Immediately-Invoked Function Expression), especially with how good angular is about wrapping things in closures itself (such as in your filter). You will insulate yourself from naming collisions thanks to the scope created by using them, but they decrease readability. They would be a bit more useful in this regard if you stored your angular modules in variables upon instantiation and used those when adding controllers/filters/etc. rather than using the module getter, but I don't recommend doing that.
If you are using a build system such as Gulp or Grunt then it might be worth having it compile these files inside of IIFE, and leaving your source without them.
I always recommend using "use strict" because it makes you write cleaner code with less chance of having casting issues. But, again, it doesn't necessarily help you "gain" anything so much as it prevents something bad from possible occurring.
Both of these are essentially safe-guards more-so than giving you some sort of advantage.
strict mode means you have less chance of running into type casting issue while self executing function is to avoid polluting global namespace.
I'm working on a a large scale angular project with a team of devs.
the problem we run into is if you have several files for a component, say a directive.
some-directive.js
some-directive-controller.js
in the definition of both files you would have to attach them to a module, however one file must create the module with []. If the developer forgets to poke around they will add [] in the second file called will actually overwrite the module. so now it becomes a memory game. Each developer has to remember to only declare the module in one file []
some-directive.js
angular.module('some-module',['some-dependencies']).directive('some-directive',function(){});
some-controller.js
angular.module('some-module',[]).controller('some-controller',function(){});
we have been using the following approach. Is there a better way?
some-directive.js
some-directive-module.js
some-directive-controller.js
where some-directive-module only contains the module creation, includes any dependencies, and does any .config needed. Still the dev needs to remember to
angular.module('some-directive') in all the other files without the square brackets.
some-directive-module.js
angular.module('some-directive',[])
.config(//someconfig stuff);
some-directive-module.js
angular.module('some-directive).directive(//declare directive);
some-directive-controller.js
angular.module('some-directive).controller(//declare contrller used by directive);
I suggested that instead we should do the following, it eliminates the issue of overwriting modules, but I received some negative feedback from one of the other devs
some-directive-module.js
angular.module('some-directive',['some-directive.directive','some-directive.controller'])
.config(//someconfig stuff);
some-directive-module.js
angular.module('some-directive.directive',[]).directive(//declare directive);
some-directive-controller.js
angular.module('some-directive.controller',[]).controller(//declare contrller used by directive);
Is there a better way? Or is one of the above options correct?
The recommended way (by multiple competent people) is to use the setter-getter-syntax (creating once with angular.module("someModule",[]) and accessing with angular.module("someModule") from there on). Putting the module definition and configuration into one file seems very clean and is common practice between a lot of developers. But make sure not to create a module for every single directive - group services, directives, constants and so on into reasonable functionality-modules instead.
Making clear what a file contains by its name is also a good idea in my opinion, so your some-directive-module.js approach seems fine to me. If developers "poke around" and "wildly add []", they should get a slap on the wrist follwoed by an explanation how modules work in angular, so they stop doing it ;-)
I ran across this in a book called ng-book by Ari Lerner.
"The compile option by itself is not explicitly used very often; however, the link function is used
very often."
Also, I refer this page but still this confuse me (Difference between the 'controller', 'link' and 'compile' functions when defining a directive)
Can someone justify this a little bit further?
Keep in mind that compile is used to return the linking function that allows the template to be bound to the scope. The cases where you need to interject yourself into this process are mainly limited to the need to actually manipulate the template prior to that binding. One example would be to modify the template based on the attributes set by the user. In short most developers forget about compile unless they need to modify the template. 'Most' are more concerned with the instance of their directive and what to do with the scope bound to that instance (domain of the linking function).
I am using 'Most' very loosely as I have absolutely no data regarding this.
Necessitating the injection of a service in a controller in order to have access to data and/or functions can be thought of as both a pro and a con.
What I'm trying to determine is what are the objective "pitfalls" of utilizing the $rootScope for often used bits of data and or functions?
(Note: I'm not trying to start a religious war here, but instead be able to make well informed decisions.)
It's like polluting of global namespace in plain JavaScript. You are polluting your application's global space. It's never good to do that (in any of the languages).
But there are some reasonable usages of rootScope...Angular says:
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
I'd like to know if using
angular.extend($scope,MyService);
Does it break oop encapsulation principle ?
Does it smell like MyService.call($scope) ?
Could you face variable and function conflicts ?
Is this a bad/good practice?
Typically from my experience services are injected into the controller and then will be called from that scope. I wouldn't say that using extend to copy over functions and properties is necessarily bad, but it might mitigate some of the purposes of IoC (inversion of control), which is what injection in angular is based on.
Does it break oop...?
My understanding is that what you would get from this call is additional functions and service calls directly on your scope. This doesn't break OOP in the sense that scope is an object and would have functions applied. Provided those functions + properties make sense on the scope it seems like a fine thing to do from that perspective.
Does it smell like MyService.call($scope)?
As I said in the first paragraph - I don't see why you wouldn't just call the service and either share data or pass in references to objects to the service. Another pattern that is common in angular is to use a promise to process returned data in your scope. That looks like:
MyService.callFunction(parameters).then(function (data) {
// process data here. Since this runs in $scope you can also use $scope normally.
// $scope.$apply() is in progress and will complete when the function returns
});
All the service does is provide the data to the scope then. Point is that I think there are better patterns than "extend".
Can you face conflicts?
In the call angular.extend(a, b); data, properties and functions are copied from b to a. If something already exists on a it will be overwritten with the data from b. So technically the short answer is "yes", you can face conflicts.
The bottom line
So at the end of the day this isn't a bad pattern but there are probably more common patterns I would try to use first.