ATM: Angular Module - Order of Injection

Once I had identified and dealt with the definition versus loading problem, I had a short but productive streak, only to come to a complete halt because of another cryptic problem. While the definition versus loading problem is an obvious mistake (albeit easy to make, easy to overlook, and hard to diagnose), my next cryptic problem was not one that I, or the senior programmers that were kindly helping me, even knew to look for.

Symptoms

FYI

In both the Firefox and Chrome consoles, the following lines are generated by console.log commands within my code, including the eventFactory –the very same eventFactory that clearly had a properly written getEventData method– …

1
2
3
4
eventFactory instantiated
eventData ...
Object { meta: Object, acts: Array[11] } // this is my mock eventData array
eventController.getEventData() return value is ...

Firefox

  • My html showed up, but my controller variables weren’t being displayed.
  • My Firefox console showed…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol. index.html
"eventFactory instantiated" eventFactory.js:7
"eventData ..." eventFactory.js:144
Object { meta: Object, acts: Array[11] } eventFactory.js:145
"eventController.getEventData() return value is ..." eventController.js:11
"Error: eventFactory.getEventData is not a function
app<@file:///Users/metasean/projects/stage-hand/js/eventController.js:12:3
d@file:///Users/metasean/projects/stage-hand/js/angular.min.js:35:27
f/<.instantiate@file:///Users/metasean/projects/stage-hand/js/angular.min.js:35:163
Pd/this.$get</<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:67:415
N/<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:54:23
r@file:///Users/metasean/projects/stage-hand/js/angular.min.js:7:369
N@file:///Users/metasean/projects/stage-hand/js/angular.min.js:53:393
g@file:///Users/metasean/projects/stage-hand/js/angular.min.js:47:256
z/<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:46:374
fc/c/</<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:18:310
Zd/this.$get</k.prototype.$eval@file:///Users/metasean/projects/stage-hand/js/angular.min.js:112:57
Zd/this.$get</k.prototype.$apply@file:///Users/metasean/projects/stage-hand/js/angular.min.js:112:341
fc/c/<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:18:268
d@file:///Users/metasean/projects/stage-hand/js/angular.min.js:35:27
fc/c@file:///Users/metasean/projects/stage-hand/js/angular.min.js:18:248
fc@file:///Users/metasean/projects/stage-hand/js/angular.min.js:18:380
Xc@file:///Users/metasean/projects/stage-hand/js/angular.min.js:17:422
@file:///Users/metasean/projects/stage-hand/js/angular.min.js:215:30
a@file:///Users/metasean/projects/stage-hand/js/angular.min.js:145:67
oe/c/<@file:///Users/metasean/projects/stage-hand/js/angular.min.js:31:223
r@file:///Users/metasean/projects/stage-hand/js/angular.min.js:7:288
oe/c@file:///Users/metasean/projects/stage-hand/js/angular.min.js:31:207
"
e/<() angular.min.js:92
Rd/this.$get</<() angular.min.js:68
Zd/this.$get</k.prototype.$apply() angular.min.js:112
fc/c/<() angular.min.js:18
d() angular.min.js:35
fc/c() angular.min.js:18
fc() angular.min.js:18
Xc() angular.min.js:17
<anonymous> angular.min.js:215
a() angular.min.js:145
oe/c/<() angular.min.js:31
r() angular.min.js:7
oe/c() angular.min.js:31

Canary Chrome

  • My Chrome console showed…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
eventFactory instantiated
eventFactory.js:144 eventData ...
eventFactory.js:145 Object {meta: Object, acts: Array[11]}
eventController.js:11 eventController.getEventData() return value is ...
angular.min.js:92 TypeError: undefined is not a function
at new <anonymous> (eventController.js:12)
at d (angular.min.js:35)
at Object.instantiate (angular.min.js:35)
at angular.min.js:67
at angular.min.js:54
at r (angular.min.js:7)
at N (angular.min.js:53)
at g (angular.min.js:47)
at angular.min.js:46
at angular.min.js:18

Mistake

So, what was my mistake?

I had the following [1]…

1
.controller('MainCtrl', ['$scope', 'eventFactory', function(eventFactory, $scope) {

instead of …

1
.controller('MainCtrl', ['$scope','eventFactory', function($scope, eventFactory) {

Note the order of $scope and eventFactory at the beginning of the array in comparison to their parameter order in the anonymous function.

Explanation

As I mentioned previously, the senior (relatively) programmers and I didn’t even suspect that this could cause a problem. At least we didn’t until I demonstrated that it did. But I had stumbled across the solution and no one in the group could explain why the mismatched order would cause a failure. We all knew that order doesn’t matter in arrays; only t clearly did in this context.

Thankfully, shortly after our cohort started, I was given a copy of “AngularJS Up & Running” by Shyam Seshadri & Brad Green. I’ve been busy enough with work and coursework that I didn’t even open it until a couple of weekends ago. At that point, I did a quick skim, looking specifically for information on $q and found it lacking in that area. I started skimming it in a little more depth yesterday, and wow; I can’t wait for a chance to go through it page by page! In the meantime, one of the tidbits I stumbled across explained why the above code failed, and it makes perfect sense.

First some more background is useful. Historically, if the modules being injected were not included, as strings, in the array with the anonymous function, then minification would functionally obfuscate the module name and the code wouldn’t work once minified. So the “Safe Style of Dependency Injection” should be used if the code is going to be minified. While there are steps toward rectifying the underlying problems, the safe style is still recommended. I strongly suggest checking out the textbox on pages 75-76 of “AngularJS Up & Running” for more information.

So why does the order of injection matter?

Well, the parameters that are used by the anonymous function are determined based on the order of the preceding items in the array. Hence, in

1
.controller('MainCtrl', ['$scope', 'eventFactory', function(eventFactory, $scope) {

the first parameter eventFactory is being assigned the '$scope' module, while the $scope parameter represents the 'eventFactory' module. So, clearly things aren’t going to work as expected! Mystery solved.