Angular.js: Is .value() the proper way to set app wide constant and how to retrieve it in a controller
Asked Answered
S

3

90

Hi there I was watching a couple of the angular.js videos and saw that the value() method was used to set a kind of module-wide constant. for example, one can set the Angular-UI library's config like so: (coffeescript)

angular.module('app',[])
.value "ui.config", 
  tinymce:
    theme: 'simple'
    width: '500'
    height: '300'

And my app is currently looking like this:

window.app = angular.module("app", [ 'ui'])

.config(["$routeProvider", ($routeProvider) ->
  $routeProvider
  .when "/users",
    templateUrl: "assets/templates/users/index.html"
    controller: IndexUsersCtrl

  .otherwise redirectTo: "/users"

])

.value 'csrf', $('meta[name="csrf-token"]').attr('content') #<---- attention here

IndexUsersCtrl = ($scope) ->
  $scope.users = gon.rabl
  console.log "I want to log the csrf value here" #<---- then attention
IndexUsersCtrl.$inject = ['$scope']

But I can't seem to get that value by tapping into the 'app' variable which is corresponding to the app module.

I read up here on ST and over on angularjs's google group that one way to share common code btwn controllers is through a service, will this concept apply here, too?

Thanks!

Saponaceous answered 22/10, 2012 at 16:18 Comment(1)
In case you're not aware, the $http service has some CSRF capabilities. See section "Cross Site Request Forgery (XSRF) Protection" here: docs.angularjs.org/api/ng.$httpPeplum
M
150

Module.value(key, value) is used to inject an editable value, Module.constant(key, value) is used to inject a constant value

The difference between the two isn't so much that you "can't edit a constant", it's more that you can't intercept a constant with $provide and inject something else.

// define a value
app.value('myThing', 'weee');

// define a constant
app.constant('myConst', 'blah');

// use it in a service
app.factory('myService', ['myThing', 'myConst', function(myThing, myConst){
   return {
       whatsMyThing: function() { 
          return myThing; //weee
       },
       getMyConst: function () {
          return myConst; //blah
       }
   };
}]);

// use it in a controller
app.controller('someController', ['$scope', 'myThing', 'myConst', 
    function($scope, myThing, myConst) {
        $scope.foo = myThing; //weee
        $scope.bar = myConst; //blah
    });
Munshi answered 22/10, 2012 at 16:33 Comment(16)
how does the 'myService' token fit in to the picture?Beanfeast
@DaveEdelhart, Sorry I didn't see your question earlier. I just had it in there as an example of a service that used the value. Fortunately, Pavel Hlobil is a good Samaritan and he added some annotation to my code to make that clearer.Munshi
Do you know if the value is read-only? I was not able to find .value() in the documentation...Jemy
No it's not "read only". If you were to put an object in there, anything could alter that object's properties. This is mostly because it's JavaScript, and not because of any particular design concern on Angular's part. However, I've not seen value used in a way that it's being altered, usually I've just seen it used for injectible "constants".Munshi
@blesh, javascript has readonly properties, so i don't think it's a restriction of the languageElison
@EliranMalka JS has readonly properties, only so long as whatever engine is executing that JS honors readonly properties. Many versions of IE do not support readonly properties. I'm not sure about newer versions of IE.Munshi
@blesh there is $provider.constant() for that (which is probably what poster needs). constant()s are immutable, value()s can be messed with.Twigg
However constants are NOT immutable. You just can't overwrite them with another injection because $provide won't intercept them for decoration.Munshi
@blesh Isn't it the inability to intercept/overwrite/modify the value that defines the constant as immutable? Related thread in the angular mailing list with a jsBin here: groups.google.com/forum/#!topic/angular/vhSaHB3CQKYTwigg
you can still modify anything defined in an angular constant, at least in the context of whatever you inject it into. So it's not really "constant", in the classical sense. Take this plunk for example You can modify it and it carries over from one controller to the next. You can't, however, intercept it with $provide. Which is the only difference between .constant() and .value()Munshi
Because JavaScript passes primitive types by value, the controller or service would need to call app.value('myThing', newValue) to change myThing. However, in my tests this didn't work (myThing keeps its value when the controller is invoked again). How can the controller modify myThing?Reste
@DanDascalescu if you want to be able to alter any primitive value passed to any function, regardless of it being in Angular or not, you'll have to pass it as part of a reference type like an Array or Object.Munshi
I know this is an old answer, but "Module.value(key, value) is used to inject an editable value, Module.constant(key, value) is used to inject a constant value" doesn't tally with ng in its latest incarnation (1.3.4). The difference between module.value() and module.constant() is that: a constant() is available earlier in your app's lifecycle (during config and run); value() is only available during run. Whether they are mutable, and where changed values are visible, depends on their value's structure (primitive or not). docs.angularjs.org/guide/providers#constant-recipeVelamen
How will you decorate your value?Pipistrelle
@Velamen Could you or anybody give an example where a constant can be changed? According a more recent answer, a constant should be never changed. Can be, though?Insurgence
@Insurgence generally a "constant" is regarded as (and is) immutable, but when dealing with objects this is nuanced. If you have a constant that is an object structure, for example: app.constant('constantName', { aProp: aValue }); aValue is mutable and can therefore be changed. hth.Velamen
K
4

I recently wanted to use this feature with Karma inside a test. As Dan Doyon points out the key is that you would inject a value just like a controller, service, etc. You can set .value to many different types - strings, arrays of objects, etc. For example:

myvalues.js a file containing value - make sure it is including in your karma conf file

var myConstantsModule = angular.module('test.models', []);
myConstantModule.value('dataitem', 'thedata');
// or something like this if needed
myConstantModule.value('theitems', [                                                                                                                                                                                                             
  {name: 'Item 1'},                                                                                                                                                                                                                         
  {name: 'Item 2'},                                                                                                                                                                                                                         
  {name: 'Item 3'}
]);                                                                                                                                                                                                                         

]);

test/spec/mytest.js - maybe this is a Jasmine spec file loaded by Karma

describe('my model', function() {
    var theValue;
    var theArray;
    beforeEach(module('test.models'));
    beforeEach(inject(function(dataitem,theitems) {
      // note that dataitem is just available
      // after calling module('test.models')
      theValue = dataitem;
      theArray = theitems;
    });
    it('should do something',function() {
      // now you can use the value in your tests as needed
      console.log("The value is " + theValue);
      console.log("The array is " + theArray);
    });
});
Kastner answered 18/5, 2013 at 15:10 Comment(0)
O
2

You need to reference csrf in your controller IndexUsersCtrl = ( $scope, csrf )

IndexUsersCtrl.$inject = [ '$scope', 'csrf' ]
Orissa answered 22/10, 2012 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.