Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 38fbe3e

Browse files
shahatapetebacondarwin
authored andcommitted
feat($cookies): move logic into $cookies and deprecate $cookieStore
The new API on `$cookies` includes: * `get` * `put` * `getObject` * `putObject` * `getAll` * `remove` The new API no longer polls the browser for changes to the cookies and no longer copy cookie values onto the `$cookies` object. The polling is expensive and caused issues with the `$cookies` properties not synchronizing correctly with the actual browser cookie values. The reason the polling was originally added was to allow communication between different tabs, but there are better ways to do this today (for example `localStorage`). DEPRECATION NOTICE: `$cookieStore` is now deprecated as all the useful logic has been moved to `$cookies`, to which `$cookieStore` now simply delegates calls. BREAKING CHANGE: `$cookies` no longer exposes properties that represent the current browser cookie values. Now you must explicitly the methods described above to access the cookie values. This also means that you can no longer watch the `$cookies` properties for changes to the browser's cookies. This feature is generally only needed if a 3rd party library was programmatically changing the cookies at runtime. If you rely on this then you must either write code that can react to the 3rd party library making the changes to cookies or implement your own polling mechanism. Closes #6411 Closes #7631
1 parent 997fdea commit 38fbe3e

File tree

4 files changed

+145
-191
lines changed

4 files changed

+145
-191
lines changed

src/ngCookies/cookieStore.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ angular.module('ngCookies').
44
/**
55
* @ngdoc service
66
* @name $cookieStore
7+
* @deprecated
78
* @requires $cookies
89
*
910
* @description
@@ -13,6 +14,11 @@ angular.module('ngCookies').
1314
*
1415
* Requires the {@link ngCookies `ngCookies`} module to be installed.
1516
*
17+
* <div class="alert alert-error">
18+
* **Note:** The $cookieStore service is deprecated.
19+
* Please use the {@link ngCookies.$cookies `$cookies`} service instead.
20+
* </div>
21+
*
1622
* @example
1723
*
1824
* ```js
@@ -41,8 +47,7 @@ angular.module('ngCookies').
4147
* @returns {Object} Deserialized cookie value, undefined if the cookie does not exist.
4248
*/
4349
get: function(key) {
44-
var value = $cookies[key];
45-
return value ? angular.fromJson(value) : value;
50+
return $cookies.getObject(key);
4651
},
4752

4853
/**
@@ -56,7 +61,7 @@ angular.module('ngCookies').
5661
* @param {Object} value Value to be stored.
5762
*/
5863
put: function(key, value) {
59-
$cookies[key] = angular.toJson(value);
64+
$cookies.putObject(key, value);
6065
},
6166

6267
/**
@@ -69,7 +74,7 @@ angular.module('ngCookies').
6974
* @param {string} key Id of the key-value pair to delete.
7075
*/
7176
remove: function(key) {
72-
delete $cookies[key];
77+
$cookies.remove(key);
7378
}
7479
};
7580

src/ngCookies/cookies.js

+84-76
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ angular.module('ngCookies', ['ng']).
2525
* @description
2626
* Provides read/write access to browser's cookies.
2727
*
28-
* Only a simple Object is exposed and by adding or removing properties to/from this object, new
29-
* cookies are created/deleted at the end of current $eval.
30-
* The object's properties can only be strings.
28+
* BREAKING CHANGE: `$cookies` no longer exposes properties that represent the
29+
* current browser cookie values. Now you must use the get/put/remove/etc. methods
30+
* as described below.
3131
*
3232
* Requires the {@link ngCookies `ngCookies`} module to be installed.
3333
*
@@ -37,87 +37,95 @@ angular.module('ngCookies', ['ng']).
3737
* angular.module('cookiesExample', ['ngCookies'])
3838
* .controller('ExampleController', ['$cookies', function($cookies) {
3939
* // Retrieving a cookie
40-
* var favoriteCookie = $cookies.myFavorite;
40+
* var favoriteCookie = $cookies.get('myFavorite');
4141
* // Setting a cookie
42-
* $cookies.myFavorite = 'oatmeal';
42+
* $cookies.put('myFavorite', 'oatmeal');
4343
* }]);
4444
* ```
4545
*/
46-
factory('$cookies', ['$rootScope', '$browser', '$$cookieReader', '$$cookieWriter', function($rootScope, $browser, $$cookieReader, $$cookieWriter) {
47-
var cookies = {},
48-
lastCookies = {},
49-
lastBrowserCookies,
50-
runEval = false,
51-
copy = angular.copy,
52-
isUndefined = angular.isUndefined;
46+
factory('$cookies', ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) {
47+
return {
48+
/**
49+
* @ngdoc method
50+
* @name $cookies#get
51+
*
52+
* @description
53+
* Returns the value of given cookie key
54+
*
55+
* @param {string} key Id to use for lookup.
56+
* @returns {string} Raw cookie value.
57+
*/
58+
get: function(key) {
59+
return $$cookieReader()[key];
60+
},
5361

54-
//creates a poller fn that copies all cookies from the $browser to service & inits the service
55-
$browser.addPollFn(function() {
56-
var currentCookies = $$cookieReader();
57-
if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
58-
lastBrowserCookies = currentCookies;
59-
copy(currentCookies, lastCookies);
60-
copy(currentCookies, cookies);
61-
if (runEval) $rootScope.$apply();
62-
}
63-
})();
64-
65-
runEval = true;
66-
67-
//at the end of each eval, push cookies
68-
//TODO: this should happen before the "delayed" watches fire, because if some cookies are not
69-
// strings or browser refuses to store some cookies, we update the model in the push fn.
70-
$rootScope.$watch(push);
71-
72-
return cookies;
62+
/**
63+
* @ngdoc method
64+
* @name $cookies#getObject
65+
*
66+
* @description
67+
* Returns the deserialized value of given cookie key
68+
*
69+
* @param {string} key Id to use for lookup.
70+
* @returns {Object} Deserialized cookie value.
71+
*/
72+
getObject: function(key) {
73+
var value = $$cookieReader()[key];
74+
return value ? angular.fromJson(value) : value;
75+
},
7376

77+
/**
78+
* @ngdoc method
79+
* @name $cookies#getAll
80+
*
81+
* @description
82+
* Returns a key value object with all the cookies
83+
*
84+
* @returns {Object} All cookies
85+
*/
86+
getAll: function() {
87+
return $$cookieReader();
88+
},
7489

75-
/**
76-
* Pushes all the cookies from the service to the browser and verifies if all cookies were
77-
* stored.
78-
*/
79-
function push() {
80-
var name,
81-
value,
82-
browserCookies,
83-
updated;
84-
85-
//delete any cookies deleted in $cookies
86-
for (name in lastCookies) {
87-
if (isUndefined(cookies[name])) {
88-
$$cookieWriter(name, undefined);
89-
}
90-
}
91-
92-
//update all cookies updated in $cookies
93-
for (name in cookies) {
94-
value = cookies[name];
95-
if (!angular.isString(value)) {
96-
value = '' + value;
97-
cookies[name] = value;
98-
}
99-
if (value !== lastCookies[name]) {
100-
$$cookieWriter(name, value);
101-
updated = true;
102-
}
103-
}
90+
/**
91+
* @ngdoc method
92+
* @name $cookies#put
93+
*
94+
* @description
95+
* Sets a value for given cookie key
96+
*
97+
* @param {string} key Id for the `value`.
98+
* @param {string} value Raw value to be stored.
99+
*/
100+
put: function(key, value) {
101+
$$cookieWriter(key, value);
102+
},
104103

105-
//verify what was actually stored
106-
if (updated) {
107-
updated = false;
108-
browserCookies = $$cookieReader();
104+
/**
105+
* @ngdoc method
106+
* @name $cookies#putObject
107+
*
108+
* @description
109+
* Serializes and sets a value for given cookie key
110+
*
111+
* @param {string} key Id for the `value`.
112+
* @param {Object} value Value to be stored.
113+
*/
114+
putObject: function(key, value) {
115+
$$cookieWriter(key, angular.toJson(value));
116+
},
109117

110-
for (name in cookies) {
111-
if (cookies[name] !== browserCookies[name]) {
112-
//delete or reset all cookies that the browser dropped from $cookies
113-
if (isUndefined(browserCookies[name])) {
114-
delete cookies[name];
115-
} else {
116-
cookies[name] = browserCookies[name];
117-
}
118-
updated = true;
119-
}
120-
}
118+
/**
119+
* @ngdoc method
120+
* @name $cookies#remove
121+
*
122+
* @description
123+
* Remove given cookie
124+
*
125+
* @param {string} key Id of the key-value pair to delete.
126+
*/
127+
remove: function(key) {
128+
$$cookieWriter(key, undefined);
121129
}
122-
}
130+
};
123131
}]);

test/ngCookies/cookieStoreSpec.js

+16-47
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,27 @@
11
'use strict';
22

33
describe('$cookieStore', function() {
4-
var mockedCookies;
5-
6-
beforeEach(function() {
7-
var lastCookies = {};
8-
mockedCookies = {};
9-
module('ngCookies', {
10-
$$cookieWriter: function(name, value) {
11-
mockedCookies[name] = value;
12-
},
13-
$$cookieReader: function() {
14-
if (!angular.equals(lastCookies, mockedCookies)) {
15-
lastCookies = angular.copy(mockedCookies);
16-
mockedCookies = angular.copy(mockedCookies);
17-
}
18-
return mockedCookies;
19-
}
20-
});
21-
});
22-
23-
it('should serialize objects to json', inject(function($cookieStore, $$cookieReader, $rootScope) {
24-
$cookieStore.put('objectCookie', {id: 123, name: 'blah'});
25-
$rootScope.$digest();
26-
expect($$cookieReader()).toEqual({'objectCookie': '{"id":123,"name":"blah"}'});
4+
5+
beforeEach(module('ngCookies', {
6+
$cookies: jasmine.createSpyObj('$cookies', ['getObject', 'putObject', 'remove'])
277
}));
288

299

30-
it('should deserialize json to object', inject(function($cookieStore, $browser, $$cookieWriter) {
31-
$$cookieWriter('objectCookie', '{"id":123,"name":"blah"}');
32-
$browser.poll();
33-
expect($cookieStore.get('objectCookie')).toEqual({id: 123, name: 'blah'});
10+
it('should get cookie', inject(function($cookieStore, $cookies) {
11+
$cookies.getObject.andReturn('value');
12+
expect($cookieStore.get('name')).toBe('value');
13+
expect($cookies.getObject).toHaveBeenCalledWith('name');
3414
}));
3515

3616

37-
it('should delete objects from the store when remove is called', inject(function($cookieStore, $browser, $rootScope, $$cookieReader) {
38-
$cookieStore.put('gonner', { "I'll":"Be Back"});
39-
$rootScope.$digest(); //force eval in test
40-
$browser.poll();
41-
expect($$cookieReader()).toEqual({'gonner': '{"I\'ll":"Be Back"}'});
42-
43-
$cookieStore.remove('gonner');
44-
$rootScope.$digest();
45-
expect($$cookieReader()).toEqual({});
17+
it('should put cookie', inject(function($cookieStore, $cookies) {
18+
$cookieStore.put('name', 'value');
19+
expect($cookies.putObject).toHaveBeenCalledWith('name', 'value');
4620
}));
47-
it('should handle empty string value cookies', inject(function($cookieStore, $browser, $rootScope, $$cookieReader) {
48-
$cookieStore.put("emptyCookie",'');
49-
$rootScope.$digest();
50-
expect($$cookieReader()).
51-
toEqual({ 'emptyCookie': '""' });
52-
expect($cookieStore.get("emptyCookie")).toEqual('');
53-
54-
mockedCookies['blankCookie'] = '';
55-
$browser.poll();
56-
expect($cookieStore.get("blankCookie")).toEqual('');
21+
22+
23+
it('should remove cookie', inject(function($cookieStore, $cookies) {
24+
$cookieStore.remove('name');
25+
expect($cookies.remove).toHaveBeenCalledWith('name');
5726
}));
58-
});
27+
});

0 commit comments

Comments
 (0)