2

I'm in the middle of refactoring my ngTrader game by following the angularjs-google-style to have all my controllers, services, directives, ect... defined as classes, with functions defined as prototypes on those classes, then registering the class with angular.

The issue is getting these changes it to work with closure-library's goog.provide() and goog.require(). With the setup below, I get an angular error that says

Failed to instantiate module ngTrader due to:
Error: [$injector:modulerr] Failed to instantiate module ngTrader.account due to:
Error: [ng:areq] Argument 'fn' is not a function, got undefined

Index.html

<body ng-app="ngTrader">
    ....
    <script src="bower_components/closure-library/closure/goog/base.js"></script>
    <script src="components/account/accountSrvc.js"></script>
    <script src="components/account/account.js"></script>
    <script src="app.js"></script>   
</body>

I've tried various orders of these files, thinking that the load order will affect what is available and what is not. I figured that the order shouldn't matter since that's what goog provide/require should fix.

  • app.js, account.js, accountSrvc.js
  • app.js, accountSrvc.js, account.js
  • accountSrvc.js, account.js, app.js

app.js

goog.provide('ngTrader');
goog.require('ngTrader.account');

ngTrader = angular.module('ngTrader', [ngTrader.account.name]);

account.js

goog.provide('ngTrader.account');
goog.require('ngTrader.account.accountSrvc');

ngTrader.account = angular.module('ngTrader.account', []);
ngTrader.account.service('accountSrvc', ngTrader.account.accountSrvc);

Not sure if I need the goog.require() call here, the google style didn't include it their snippet. I've tried with and without it. I've also tried adding goog.require('ngTrader') here, but that would throw errors unless I moved app.js to be the first called script in index.html, which in turn would throw errors about ngTrader.account not being defined.

The service registration is done here as per the google style recommendation services example shows to put this module.service('request', hello.request.Request); in the module definition.

accountSrvc.js

goog.provide('ngTrader.account.accountSrvc');

ngTrader.account.accountSrvc = function() {....};    
ngTrader.account.accountSrvc.prototype.reset = function() {....};

I put breakpoints inside accountSrvc.js and see that the ngTrader.account object has the new accountSrvc property being added to it. But when I inspect breakpoints in account.js, the accountSrvc property is undefined.

So where am I going wrong with this, order of the scripts being loaded, how I'm using require/provide, or something else?

Any help would be appreciated. Thanks.

Jerry
  • 1,775
  • 4
  • 22
  • 40
  • I'm not a closure expert but it may be a problem with minification. You may need to explicitly define the dependencies to services, controllers etc as angular's dependency injection uses the names of parameters to inject the appropriate dependencies. Take a peek at http://docs.angularjs.org/tutorial/step_05#a-note-on-minification. – Gruff Bunny Apr 06 '14 at 21:36
  • @GruffBunny I've built this on top of yeoman's angular generator and this shows up during the serve task which does not minify the code. – Jerry Apr 06 '14 at 22:24

1 Answers1

0

Does the following help?

<body ng-app="ngTrader">
    <script src="bower_components/closure-library/closure/goog/base.js"></script>
    <script>
      goog.require("ngTrader");
    </script>
</body>

Make sure the paths in the js/libraries/goog/deps.js are set, if not you can use calcdeps to set them:

python \
 "/home/me/Software/Programming/JavaScript/Closure compiler/closure-library/closure/bin/calcdeps.py" \
 --path /var/www/html/hosts/site/public_html/js/libraries \
 --input /var/www/html/hosts/site/public_html/js/libraries/app.js \
 --output_mode deps \
 --output_file /var/www/html/hosts/gsa/public_html/js/libraries/goog/deps.js

Location and names of the files can be important as calcdeps would expect them in a certain location with a certain name. You can circomvent that by adding them with --input (I think) but rather use structured paths. See here for an example:

[update]

I could run the uncompiled code, files are in:

The google closure library is in: public_html/js/libraries/goog

Angular in: public_html/js/libraries/angular.1.0.8.js

public_html/js/libraries/app.js

public_html/js/libraries/ngTrader/account.js

public_html/js/libraries/ngTrader/account/accountSrvc.js

public_html/test.html

<body ng-app="ngTrader">
    <script src="js/libraries/angular.1.0.8.js"></script>
    <script src="js/libraries/goog/base.js"></script>
    <script>
        goog.require("ngTrader");
    </script>
</body>

Had to create deps.js with the following command:

python \
 "/path/to/closure-library/closure/bin/calcdeps.py" \
 --path /path/to/public_html/js/libraries \
 --input /path/to/public_html/js/libraries/app.js \
 --output_mode deps \
 --output_file /path/to/public_html/js/libraries/goog/deps.js
Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • I was able to run calcdeps.py to generate an updated deps.js file, but now I get an error saying `Uncaught Error: Namespace "ngTrader" already declared.`. I checked throughout my code and the only place where I have `goog.provide('ngTrader');` is in my app.js file. Here's a copy of the [deps.js](http://pastebin.com/d1ggHztF) file. If I do get this to work, would I need to run calcdeps each time I add a new file or modify the dependencies of another? – Jerry Apr 07 '14 at 13:21
  • @Jarek your deps.js do not show multiple provide or it'll be in there multiple times. If this error is in base.js (line 192 somewhere) then maybe you have a `goog.provide` in your html file? It should be a `goog.require` in your html file as that kicks off loading all the needed libraries. You should run calcdeps every time you make a new goog.provide but don't need the `--input` just have `--path` point to the root of your js files. Try running the following from the root of your project: `grep -H -r "goog.provide(.ngTrader.)" . | cut -d: -f1` – HMR Apr 07 '14 at 13:59
  • @Jarek Maybe you can check it into github as a new project and I'll have a look. – HMR Apr 07 '14 at 14:03
  • I'll create a branch and upload my changes to it later today. – Jerry Apr 07 '14 at 15:05
  • After a bit more debugging, turns out the issue was the order my code was executing, I was overriding properties on the objects provided by closure lib. Basically in accountSrvc.js I created the `ngTrader.account.accountSrvc` function and in account.js I overrode the base object, ngTrader.account, when creating the module. So when I tried to do `ngTrader.account.Service(ngTrader.account.accountSrvc)`, accountSrvc was undefined because I overrode the base object in the preceding line. I ended up moving the service registration from account.js to the bottom of accountSrvc.js. – Jerry Apr 08 '14 at 03:37