This is just a quick blog post (more of a note-to-self) to demonstrate the fact that you cannot use the revealing module pattern with Directive Controllers in AngularJS. And, just to be clear, all controllers, in AngularJS, are "directive controllers." Meaning, the ngController directive is nothing more than a directive that instantiates a "directive controller" using a lookup value instead of a raw function reference.
Directive controllers cannot use the revealing module pattern because they are created using a two-step process. First, the instance is created; then, the constructor is invoked. However, the return value of the constructor is never used to overwrite the instance value. As such, your controller's return value is ignored. More or less, the steps looks like this (paired down):
- var instance = Object.create( controllerPrototype );
- $injector.invoke( controllerFunction, instance, locals, constructor );
- return( instance );
As you can see, the result of the controller invocation (using .invoke()) is ignored. Only the Object.create() value is returned.
To see this in a demo, take a look at the following code. Notice that my directive Controller is attempting to return a new API surface area:
When the directive finally links and we log the passed-in controller instance, we get the following console output:
Notice that the object is empty - it doesn't contain the methods that we returned in the constructor.
Normally, I would never think to use the revealing module pattern with an AngularJS controller; but, when you define your controller within the lexical bounds of the directive factory, it's hard to remember that it's still a "normal" Controller. And, that it lives and dies by the same rules as every other controller.
also one thing to note In angular 1.3
angular have not recomended to write controller globally
we have to putcontroller inside angular.module only
Good point, I generally use the module to define my controllers. That said, this is not a "global" controller - it's actually contained within the lexical context of the bnTest directive. So, it is a function reference, rather than a module-lookup; but, it won't leak outside the bounds of the directive due to scoping. So, it's _not as bad_ as it could be :D
Nice article. As I use TypeScript, I always wondered if I could use closures together with typing provided by classes, without recurring to class expressions.
As of v1.4.0-beta.3, this thing is fixed.
Oh, great find! I still haven't really looked into AngularJS 1.4 yet. Things move so darn quickly and I tend to not look at things until they actually get released (meaning, I sort of ignore the betas and RCs). There's just so darn much stuff out there to learn :)
I'm also very curious to learn more about TypeScript. I was just listening to an Adventures in Angular podcast and the group was talking about TypeScript in AngularJS 2.0. It was an interesting discussion; they were all sort of agreeing that TypeScript made a lot of sense for some things, like Services and Controllers. But, that it seemed to make other things like Providers and Directives harder to create.
All I know, so far, is what I've seen in a few presentation. But, I'm excited to try it out.
I didn't got my hands at Angular 2 to see how things are going, but now, while I believe in the value proposition of TypeScript, I think it misses a few oportunities like taking advantages of closures. I really like the ability to consume .d.ts and native (global members in .ts) declarations though, it speeds up coding and refactorings.
Not sure at how TypeScript make things harder as I do all kinds of code with it, but I learned each kind of object follows a different pattern, like storing dependencies in service objects, or give up typing.
And annotations shall be the attributes in static languages made right :)
Well, I'm definitely looking forward to giving it a try. I've been a bit distracted by Node.js lately (since we're starting to use it at work). But, will be digging back into AngularJS again soon.