28

I have

<body ng-app="myApp">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular-cookies.min.js">
    </script>
</body>

Everything loads correctly.

Then in my javascript I attempt to inject ngCookies:

angular.module("myApp", ["ngCookies"]).
    config(function($cookies) {
         console.log($cookies.myCookie);
    });

But it does not seem to find $cookies:

 Unknown provider: $cookies from myApp
Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
Jeff Wong
  • 325
  • 1
  • 3
  • 4
  • 1
    As stated on Angular documentation (http://docs.angularjs.org/guide/module) - Module Loading & Dependencies - *Configuration blocks - get executed during the provider registrations and configuration phase. Only providers and constants can be injected into configuration blocks*. That's why you are getting error `Unknown provider: $cookies from myApp` as `$cookies` is a service and therefore not available in `config` block. – Tom Mar 12 '13 at 14:45

6 Answers6

29

I'm not sure what is your functional use-case but you can't inject services ($cookies is a service) inside config blocks. Only constants and providers can be injected inside config blocks.

You can inject services into run blocks but I don't know if this helps you since I'm not sure what are your trying to do with those cookies.

BTW: you seems to be mixing versions of the main angular file and the ngCookies module. This is not directly linked to your problem but this is rather odd.

pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
  • 1
    Thanks. What do you mean by "mixing versions"? Do I not need angular-cookies for the ngCookies module? – Jeff Wong Mar 13 '13 at 04:21
  • 1
    @JeffWong by mixing versions I mean that you've included the main angular module in version 1.0.3 while ngCookies in version 1.0.1. Normally both versions should be the same. – pkozlowski.opensource Mar 13 '13 at 07:14
  • run blocks were the right answer. btw what are "constants" in this context? – Jeff Wong Mar 13 '13 at 19:21
  • @pkozlowski.opensource the [angular docs](https://docs.angularjs.org/api/ngCookies/service/$cookies) has that exact example from OP, can you elaborate on the last part of your answer? – JWiley Jun 22 '17 at 01:49
11

You can inject it manually:

myApp.config(function() {
  var $cookies;
  angular.injector(['ngCookies']).invoke(['$cookies', function(_$cookies_) {
    $cookies = _$cookies_;
  }]);

  // here you can use $cookies as usual
});

You might wonder why do we have to specify ngCookies to the injector() call as WELL as to the .invoke() call?

ngCookies is name of the module (you'll need to have angular-cookies.js in your project to be able to use this module). When you create injector by calling injector() you specify which modules should be used so that services from those modules can be used.

invoke() calls a function but let's you specify which services (provided by various modules) should be passed into the function (in our case service provided by ngCookies module is named $cookies)

This solution is a bit of a hack because you are manually creating new injector separate from the one that your angular app auto-creates and uses, but it should be safe because ngCookie seems to be only using functionalities of angular that don't keep their own state and are just thin wrappers of browser functionality.

Kamil Szot
  • 17,436
  • 6
  • 62
  • 65
  • I've been doing this and it works great, until minification, at which point it breaks horribly. I noticed that _ $cookies _, if changed, breaks, despite the injector annotation that *should* be minification-safe. _$cookies_ is not available in the ngCookies source, meaning that _$cookies_ is likely part of angular's magic. Need to investigate (unless you've found a way to minify with this already....) – dudewad Oct 22 '15 at 03:30
  • FOr the record SO won't let me put underscores. Sorry for the confusion. I tried. – dudewad Oct 22 '15 at 03:31
  • @dudewad I improved my answer to work with non-angular-aware minification. – Kamil Szot Oct 22 '15 at 07:28
  • Omg thank you. This is a perfect example of where the "angular way" is *absolutely* messed up. WHY are there so many ways to do this, and only one of them works for minification? E.g., why do we have to specify ngCookies to the injector() call as WELL as to the .invoke call? And why doesn't annotation, done exactly per the "minification-safe" specification on the angular site, work even when not minified in this context? Can you shed some light on that for me, because I'm totally missing it (see here: https://docs.angularjs.org/api/auto/service/$injector#annotate) – dudewad Oct 22 '15 at 17:56
  • ...because exactly zero of the "annotation" methods they show there (which are confusing as it is since they never show you which of the methods one can use to get an instance of the injector is used) work, either when minified or not minified (at least, not in module.config). I get that this is a bit of a hack but you'd think that using cookies in a module config isn't terribly out of this world, and that they'd provide some way to make it happen. Ugh. – dudewad Oct 22 '15 at 17:58
  • @dudewad Minification messes up variable and function names. Any scheme reliant on names will blow up. You need to pass service names as strings using second or third way listed at the url you gave to be out of reach of minification. Please keep in mind that no part of angular has any opportunity to run before minification. So it has to do what it can with result of minification where the parameter names are already lost. – Kamil Szot Oct 23 '15 at 13:12
  • @dudewad You could use https://github.com/sindresorhus/gulp-ngmin or similar instead of generic minification that you are using so that angular files are minified carefully to preserve information that parameter names give to angular before minification. – Kamil Szot Oct 23 '15 at 13:13
  • @dudewad I'm in no way angular apologist. I think you are right that there should be obvious way to inject services into config, or at least cookies functionality. Possibly you could inject $cookiesProvider directly to config and use it to get instance of $cookie service to use it. I haven't tried that because I was able to get away with the solution I gave in this answer. Also it could be hard because applicaiton $injector is I think not fully initialized yet, at the time .config() runs. – Kamil Szot Oct 23 '15 at 13:40
  • yeah I agree, but I know how minification works and the way I was approaching it (which was any multitude of versions from their example pages character for character, or any multitude of combinations of other ideas) should have worked. For example when minifying a function that recieves an arg, the name of that argument should not affect whether or not minification breaks it since it's local to that function. So when changing it breaks it, it's exceptionally confusing if that's the only change. Or am I confused here? (I'm referring to the lamba function in the invoke() call) – dudewad Oct 23 '15 at 22:49
  • @dudewad Inferring which service to inject into a function from parameter names is the most magic thing in angular. Other stuff is just complex and convoluted but this is magic hack that during run-time reads source code of your function (js gives you that when you cast function to string) and pareses parameter names from it. Lack of resilience against processing steps that mess up the source code is pretty easy to guess. It's a bit insane feature but I though it was well advertised. – Kamil Szot Oct 24 '15 at 22:18
  • To be honest, if I had read enough documentation to understand that angular reads your source like that, I would have heavily considered using another framework entirely. This feels like forcing other software patterns on something that JS isn't. I'll shut up now, that's a topic for a blog post! – dudewad Oct 26 '15 at 04:37
  • Holy crap, it's threads like this that makes me think angular is doomed. What a cluster$!*#@ – user1391445 Jan 03 '16 at 22:04
  • @user1391445 Think or hope? ;-) – Kamil Szot Jan 04 '16 at 00:14
2

I encountered the same issue. the angular version and the angular cookies version didn't match. what i did to fix it is update bower.json to a working versions of both.

"angular": ">=1.2.*",
"angular-cookies": ">=1.2.*"

Then i ran:

bower install

i got this question:

Unable to find a suitable version for angular, please choose one:
1) angular#1.3.13 which resolved to 1.3.13 and is required by angular-cookies#1.3.13 
2) angular#>=1.2.x <=1.4.x which resolved to 1.3.16 and is required by oclazyload#1.0.1 
3) angular#1.4.0 which resolved to 1.4.0 and is required by angular-cookies#1.4.0 
4) angular#>=1.2.* which resolved to 1.4.0 and is required by hashve 
5) angular#>=1 which resolved to 1.4.0 and is required by angular-bootstrap#0.11.2 
6) angular#>=1.2.26 <=1.5 which resolved to 1.4.0 and is required by angular-translate#2.7.2 
7) angular#~1.x which resolved to 1.4.0 and is required by restangular#1.5.1 
8) angular#^1.2.6 which resolved to 1.4.0 and is required by angular-socket-io#0.6.1 
9) angular#>= 1.0.8 which resolved to 1.4.0 and is required by angular-ui-router#0.2.15 
10) angular#>=1.2.0 <1.5.0 which resolved to 1.4.0 and is required by angular-moment#0.10.1Prefix the choice with ! to persist it to bower.json

Then I chose 3.

and it worked.

shacharsol
  • 2,326
  • 20
  • 14
0

From https://stackoverflow.com/a/18971123/132374, it looks like you need to delare 'ngCookies' in your service module if you haven't already:

var serviceModule = angular.app('App.services', ['ngCookies']);

That worked for me. Keep in mind that $cookies only works where Angular allows you to inject services (see the accepted answer for details).

Community
  • 1
  • 1
Jon Onstott
  • 13,499
  • 16
  • 80
  • 133
0

Like everyone else stated, you cannot use the angular cookie service. However, there is no law known to man that says you cannot simply use document.cookie to access it and parse it yourself. Alternatively, you can create your own provider that gives you access to the cookies and you can inject that. Please remember that angular is simply a framework and when the framework has limitations you have to remember to use something called javascript.

Pbrain19
  • 1,975
  • 2
  • 14
  • 11
-11

You should inject with name $cookieProvider instead $cookies:

angular.module("MyApp", ["ngCookies","ngRoute"])
    .config(["$routeProvider", "$locationProvider","$cookiesProvider",
        function($routeProvider, $locationProvider, $cookies) {

        }
    ]);
mdml
  • 22,442
  • 8
  • 58
  • 66
JKaveri
  • 3
  • 1
  • How do I use $cookiesProvider to get the cookie value? – angelokh Dec 14 '13 at 20:50
  • 4
    This is a wrong answer in case anyone else is curious. There is no such thing as a $cookiesProvider service inside ngCookies. Not only that, but the factories inside of ngCookies don't get loaded until AFTER the config function runs. – urban_raccoons Jan 24 '14 at 21:02