Best way to inject data into an application without $http

373 views
Skip to first unread message

Chris Mueller

unread,
Jun 14, 2013, 3:28:36 PM6/14/13
to ang...@googlegroups.com
There is likely a great way to do this, but I just haven't discovered it yet.

What's the best way to inject initial data into an Angular application? Ideally, I want to use a JSON object to initialize $scope inside a controller.

app.js:
angular.module("app", [])
.controller("SomeCtrl", function($scope) {
    $scope.data = MY_INITIAL_DATA;
    $scope.update = function() { ... } // calls to $http service to update $scope.data
});

index.html:
<script src="app.js"></script>
<script>
angular.bootstrap(document, ["app"]);
var INITIAL_DATA = { ... }; // data generated from server
</script>

The best option I can see thus far is to make the controller dependent on some service that provides the initial data, and to not build that service in the app.js file, but to instead build it with inline JS.

app.js:
angular.module("app", ["initialData"])
.controller("SomeCtrl", function($scope, InitialData) {
    $scope.data = InitialData.data;
    $scope.update = function() { ... } // calls to $http service to update $scope.data
});

index.html:
<script src="app.js"></script>
<script>
angular.module("initialData", [])
.factory("InitialData", function() {
    return {data: {key: val}}; // generated by server/templating engine
});
angular.bootstrap(document, ["app"]);
var INITIAL_DATA = { ... }; // data generated from server
</script>

Is there a better way to do this?

Thanks!
Chris

gkappel

unread,
Jun 15, 2013, 9:12:02 AM6/15/13
to ang...@googlegroups.com
Something like
<div ng-controller="TheCtrl" ng-init='initialize({"foo":"bar"})'>

initialize would be a function in TheCtrl

Grant Rettke

unread,
Jun 15, 2013, 12:53:37 PM6/15/13
to ang...@googlegroups.com
On Fri, Jun 14, 2013 at 2:28 PM, Chris Mueller <chris....@gmail.com> wrote:
> Is there a better way to do this?

It depends. Here is how we did it, it is very simple:

1. No configuration data goes into module.config. We consider
module.config to be configuration data in and of itself, eg route
definitions and stuff so that is that. The issue is trying to use
services in there, and you can't, you may only use providers.

2. Configuration data we stick it in a json file that is unique to
dev, qa, or prod, and that gets pushed out with the app.

3. There is a service named 'Config', responsible for loading the
config, and it returns a promise. In the module.run, the config gets
loaded before any other work is done.

I guess our goal is a little different, it is not about loading a
bunch of data? Config gets used all over for url bases and stuff like
that. In your case, you might do the same thing though with a service
instead.

oneman...@gmail.com

unread,
Jun 15, 2013, 7:39:28 PM6/15/13
to ang...@googlegroups.com
We used module.constant() which allows you to inject JSON objects into module.config(). Since you are only hoping to inject into a controller, you could use module.value() instead. The code below is a variation of that in angular client side auth.


privileges.js

angular.module('clientApp')
  .constant('privileges', {
    'userRoles':
    {
      'public': 1, // 001
      'user': 2, // 010
      'admin': 4  // 100
    },

    'accessLevels':
    {
      'public': 7, // 111
      'anon': 1, // 001
      'user': 6, // 110
      'admin': 4  // 100
    }
  }
);



app.js

angular.module('clientApp', ['ngCookies', 'angular-underscore', 'ui.bootstrap'])
  .config(function ($routeProvider, $locationProvider, $httpProvider, privileges) {

    var access = privileges.accessLevels;

    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl',
        access: access.public
      })  

...

Luke Kende

unread,
Jun 16, 2013, 2:42:16 AM6/16/13
to ang...@googlegroups.com
Angular is built to be server independent, meaning, typically html and js files are not dynamically delivered by the server to the browser via PHP, .NET, etc. . If you know your initial data will never change, then yeah, using the .constant or .value could work, but doesn't sound like what you are after.  

Now, Im not sure why you wouldn't use $http or $resource, but let's assume that there's a good reason.  You could use a javascript file reference before the angular references that the server dynamically delivers:

<script src="/initial_data.php"></script> //just using php as an example that delivers javascript content

This way index.html and the angular-specific js files are not dynamic created.

If initial data is not user specific and changes only occasionally, you might implement a json file on the server that gets updates server-side as necessary, and then use $http to load it (and loads it quickly because there's no server logic happening, just a hard-coded json file), if that makes sense?

mlegenhausen

unread,
Jun 17, 2013, 4:41:07 AM6/17/13
to ang...@googlegroups.com
When possible you should try to integrate your configuration data in your build process, cause that makes you independent of a server which is important when you want to go offline or want to scale. Normally configuration data should be static and should only be changed when you update your application, so you need to rebuild it.

If you are working with grunt you can try my angular constant generator which was made exactly for this case: https://github.com/werk85/grunt-ng-constant

Grant Rettke

unread,
Jun 17, 2013, 12:14:12 PM6/17/13
to ang...@googlegroups.com
On Mon, Jun 17, 2013 at 3:41 AM, mlegenhausen <mlegen...@gmail.com> wrote:
> If you are working with grunt you can try my angular constant generator
> which was made exactly for this case:
> https://github.com/werk85/grunt-ng-constant

Nice. Are you doing target specific builds for your constants?

Here is our use case:

1. Want to support Yeoman based live coding changes and testing for
local development.
2. Want to build for distribution to one of two targets: DEV or PROD.

Using the Yo scaffold we got #1, and to add #2 we just added a target
command line argument and then when we build for distribution, we copy
over the correct configuration file.

We had wanted to do exactly what you describe, to configure it at
build time, but, to do that would have required reconfiguration for #1
and it looked like too much time so we took the simpler route.

mlegenhausen

unread,
Jun 18, 2013, 4:41:09 AM6/18/13
to ang...@googlegroups.com, gre...@acm.org
Target specific builds are supported:

ngconstant: {
  dev: [
     // define your dev constants here
     {
         dest: 'dist/config.js',
         name: 'config',
         constants: {
            'CONFIG': grunt.file.readJSON('dev-config.json')
         }
     }
  ],
  prod: [
     // define your prod constants here
     {
         dest: 'dist/config.js',
         name: 'config',
         constants: {
            'CONFIG': grunt.file.readJSON('prod-config.json')
         }
     }
  ]
}

Then use ngconstant:dev or ngconstant:prod in your task registration. Then use it as follows:

angular.module('app', ['config']).service('MyService', function(CONFIG) {
   // Use your CONFIG object here.
});

Now I think about adding the possibility to add global constant configuration which gets merged in all targets.

Grant Rettke

unread,
Jun 18, 2013, 4:03:32 PM6/18/13
to ang...@googlegroups.com
On Tue, Jun 18, 2013 at 3:41 AM, mlegenhausen <mlegen...@gmail.com> wrote:
> Target specific builds are supported:

Nice!
Reply all
Reply to author
Forward
0 new messages