Setting localstorage cookie service that contains spaces inbetween words - angularjs

I can set the cookie fine,how ever if the cookie name that I am setting is "Cookie code 1" it gets saved as
"cookie%20code%201". How do I solve this issue with the spaces in between words?
self.cookie=function(){
localStorageService.cookie.set("CookieId",decodeURIComponent(self.Id), 100000);
}

The official doc for $cookieStore says the following:
Provides a key-value (string-object) storage, that is backed by session cookies. Objects put or retrieved from this storage are automatically serialized or deserialized by angular's toJson/fromJson.
Means, serialize and unserialize (urlEncoded) happens automatically. So i promise you are using this plugin atm https://github.com/grevory/angular-local-storage#cookieget, which also serialize/unserialize. Just use localStorageService.cookie.get(key); to check the callback.
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function setAndGetItem(key) {
localStorageService.cookie.set(), "Its a cookie"); // persisted as "Its%20a%20cookie"
console.log(localStorageService.cookie.get(key)); // returns "Its a cookie"
}
//...
});

Related

How to use a CookieCollection in multiple functions

I'm setting up a web page using cookies to determine if the user already logged in, using a cookie containing his id. Problem is : The cookie is either not written or the cookie collection is not updated.
I've tried reading the documentation, but it does not define the usage of CookieCollection.
Here's the function where i write my cookie :
function displayData(){
$id = $this->getRequest()->getSession()->read('id');
$cookies = CookieCollection::createFromServerRequest($this->getRequest());
if(!$cookies->has('id')){
$cookie = (new Cookie('id'))
->withValue($id)
->withExpiry(new DateTime('+999 year'))
->withPath('/')
->withDomain('break-first.eu')
->withSecure(true)
->withHttpOnly(true);
$cookies = $cookies->add($cookie);
}
// Other stuff
}
And where I try reading it :
function index(){
$cookies = $this->getRequest()->getCookieCollection();
dd($cookies);
}
I expect having a cookie named "id", but I don't have it. Only CAKEPHP and pll_language are showing up.
First things first, CakePHP provides authentication functionality with cookie authentication, you may want to have a look at that instead of driving a custom solution.
Cookbook > Plugins > Authentication
That being said, what you're doing there will create a cookie collection object, which however is just that, a lone object somewhere in space, it won't affect the state of your application, in order for that to happen you have to actually modify the response object.
However what you're trying to do there doesn't require cookie collections in the first place, you can simply read and write cookies directly via the methods provided by the request and response objects, like:
// will be `null` in case the cookie doesn't exist
$cookie = $this->getRequest()->getCookie('id');
// responses are immutable, they need to be reassinged
this->setResponse(
$this->getResponse()->withCookie(
(new Cookie('id'))
->withValue($id)
->withExpiry(new DateTime('+999 year'))
->withPath('/')
->withDomain('break-first.eu')
->withSecure(true)
->withHttpOnly(true)
)
);
And if you where to use a cookie collection for whatever reason, then you'd use withCookieCollection() to pass it into the response:
$this->setResponse($this->getResponse()->withCookieCollection($cookies));
If you run into strict typing errors, you could for example create a custom reponse class with an overridden Response::convertCookieToArray() method and cast the string to an integer there (make sure that PHP_INT_MAX covers your target date timestamp, 32-Bit incompatibility is why the fix that landed in CakePHP 4.x, probably won't come to 3.x), something like:
src/Http/Response.php
namespace App\Http;
use Cake\Http\Cookie\CookieInterface;
use Cake\Http\Response as CakeResponse;
class Response extends CakeResponse
{
protected function convertCookieToArray(CookieInterface $cookie)
{
$data = parent::convertCookieToArray($cookie);
$data['expire'] = (int)$data['expire'];
return $data;
}
}
You can pass that into the app in your webroot/index.php file, as the second argument of the $server->run() call:
// ...
$server->emit($server->run(null, new \App\Http\Response()));
See also
Cookbook > Request & Response Objects > Request > Cookies
Cookbook > Request & Response Objects > Response > Setting Cookies

maintaining session from server application in angularjs

I have an angularjs application, in this application I have a login form when I submit it I call a rest service to authenticate the user to my server application, as following :
$http.get('http://localhost:8080/user', {
headers : credentials ? {
authorization : "Basic "
+ btoa(credentials.username + ":"
+ credentials.password)
} : {};
}).then(function(response) {
if (response.data.name) {
$rootScope.authenticated = true;
$rootScope.username=response.data.name;
$rootScope.roles=response.data.authorities;
$rootScope.sessionid=response.data.details.sessionId;
} else {
$rootScope.authenticated = false;
}
}, function() {
$rootScope.authenticated = false;
});
So the $rootScope will have all the informations about the authenticated user, but when I refresh my application, all those informations I attached to $rootScope are removed.
Notice that http://localhost:8080/user will always maintain the session.
How can I solve that ?
You can either store it in sessionStorage or just get the current user logged from server side. Then in order to retrieve them use an angular.run
angular.run(...function($http, $rootScope){
// either use session storage or $http to retrieve your data and store them in $rootScope.
// if you use $http i suggest you to store the promise of $http to be sure in your controller/route to wait that it has been resolved.
});
The fact that you're loosing what you store when using f5 is normal, you lose all javascript context when doing so. The usage of angular.run permit to use the request before any controller is called However with $http you may need to wait the end of the promise. So it's better to have a reference to the promise store in $rootScope to be able to use it in the javascript part. You can reference directly the data in the templates as they will get refresh as soon they will be loaded.
Check for Local and Session storage service. You can easily attach informations to variables with getters and setters, and retrieving them through page refreshing.
Example: You can set a variable like this:
localStorageService.set('myVar', data);
And then retrieve it in another controller, after refreshing, or elsewhere in your application with:
localStorageService.get('myVar');
It is rather well documented and easy to use.

Passing data to another page using AngularJs

I am trying to pass data from one page to another using AngularJs service but whatever value I set in the variables in the service on one page, it is lost on redirection. Is there any particular way to perform the redirection? Below is the flow of my code
//Created a service to pass data
angular.module('Test').service('TestService', function() {
var new_data;
this.addData = function(page_data) {
new_data = page_data;
}
this.getData = function(){
return new_data;
}
});
//Code in controller A:
TestService.addData(data);
$window.location.href = "/static/html/buyer-cart-confirmation.html"
//Code in controller B:
data = TestService.getData();
No data is received in controller B. Can somebody please help me with this.
Thank you!
You can use session storage to serialize / deserialize data across different instances of angular within the same session (tab), and you can use local storage to do the same thing across sessions, (new tab). Here is the code for both:
Session Storage
class SessionStorageService
setStorage:(key, value) ->
json = if value? then JSON.stringify value else null
sessionStorage.setItem key, json
getStorage:(key)->
JSON.parse sessionStorage.getItem key
pageData1:(value=null) ->
#accessor 'pageData1', value
pageData2:(value=null) ->
#accessor 'pageData2', value
# more data values defined here
accessor:(name, value)->
return #getStorage name unless value?
#setStorage name, value
angular
.module 'app.Services'
.service 'sessionStorageService', SessionStorageService
Local Storage Service
class LocalStorageService
setStorage:(key, value) ->
json = if value? then JSON.stringify value else null
localStorage.setItem key, json
getStorage:(key)->
JSON.parse localStorage.getItem key
clear: ->
#setStorage(key, null) for key of localStorage
pageData1:(value=null) ->
#accessor 'pageData1', value
pageData2:(value=null) ->
#accessor 'pageData2', value
# more data values defined here
accessor:(name, value)->
return #getStorage name unless value?
#setStorage name, value
angular
.module 'app.Services'
.service 'localStorageService', LocalStorageService
With that said, you need to ask yourself why you are redirecting to a different page with any expectation that your state will somehow be preserved?
Angular is typically used for Single Page Applications that use routing frameworks like ui-router to manage state transformations, rather than the old-school, click-and-refresh-the-page model.
In other words, you should not redirect unless you intend on starting a brand new Angular application.
I think your logic is wrong, and since you don't provide a Plunker I can't test it at the moment. I think you should go with smth like:
angular.module('Test').service('TestService', function() {
this.addData = function(page_data) {
this.new_data = page_data;
};
return this;
});
and then you access your data like this:
TestService.new_data
I think it will work like this.

Is it suitable to use $httpBackend in production to abstract data service requests?

I have a data service in my application that is responsible for retrieving information for my controllers. This information might come from local storage, window or an ajax request. The problem I am facing is the $q promise responses don't look like $http responses.
this.getContactDetails = function(data) {
// The first time this method is called, we expect contact details to be preloaded on the page.
// We want to read and return that object then remove it from the page so subsequent requests are to the server.
if(typeof $window.preloadData.contact !== 'undefined') {
var contactDetails = JSON.parse(JSON.stringify($window.preloadData.contact));
delete $window.preloadData.contact;
// Since the method call should always have the same return type, we manually create a deferred object and set the resolution using the $q service.
var deferred = $q.defer();
deferred.resolve(contactDetails);
return deferred.promise;
}
var request = requests.contactDetails.get;
return $http(request);
};
The $q service does a nice job here but it resolves as the object it was given. I wouldn't really expect it to wrap the response. I know $httpBackend could accomplish this.
$httpBackend.whenGET(request).respond(contactDetails);
But the service is used in the MockE2E library and I doubt this was its intended use. I am not sure how to call this off afterwards or what would happen if I used it twice on the same request but I can figure out these questions. My other concern is that there doesn't seem to be a way to pass the same config object to $httpBackend as I do to $http. $httpBackend only accepts a method, url, body and headers, while $http config allows me to specify parameters.
Currently my work-around is simply to create and $http-like wrapper myself.
var contactDetails = JSON.parse(JSON.stringify({
data: $window.preloadData.contact
}));
But I don't find this very elegant. Is there a better/correct way to do this?
You can implement your storage layer as a $cacheFactory and add it to $httpProvider during the configuration phase.
From the docs:
When the cache is enabled, $http stores the response from the server in the specified cache. The next time the same request is made, the response is served from the cache without sending a request to the server.
Hence, if you provide your own implementation of a cache with the following methods:
{object} info() — Returns id, size, and options of cache.
{{*}} put({string} key, {*} value) — Puts a new key-value pair into the cache and returns it.
{{*}} get({string} key) — Returns cached value for key or undefined for cache miss.
{void} remove({string} key) — Removes a key-value pair from the cache.
{void} removeAll() — Removes all cached values.
{void} destroy() — Removes references to this cache from $cacheFactory.
You can return values read from localStorage, session cookies, etc. and they will be treated as there were data sent from the server, just without the AJAX request.

How can I use angular-cache in conjunction with the AngularJS LocalStorageModule

I have an application that when it starts gets a list of admin users.
The data looks something like this:
var users =
[
{"id":"527ddbd5-14d3-4fb9-a7ae-374e66f635d4","name":"x"},
{"id":"966171f8-4ea1-4008-b6ac-d70c4eee797b","name":"y"},
{"id":"de4e89fe-e1de-4751-9605-d6e1ec698f49","name":"z"}
]
I have a call that gets this data:
os.getUserProfiles($scope);
and the function:
getUserProfiles: function ($scope) {
$http.get('/api/UserProfile/GetSelect')
.success(function (data, status, headers, config) {
$scope.option.userProfiles = data;
});
},
I would like to avoid the admin users having to continuously issue the requests to get
the user list. I was looking at the $cacheFactory in Angular but this does not really
seem to meet my needs.
The angular-cache that's on github looks interesting but I'm not quite sure how to use
it with objects like this and then have the data stored using the LocalStorageModule.
Can someone give me an example of how they have used this product with the LocalStorageModule.
I would suggest check the extended angular-cache.
As described in documentation: http://jmdobry.github.io/angular-cache/guide.html#using-angular-cache-with-localStorage
app.service('myService', function ($angularCacheFactory) {
// This cache will sync itself with localStorage if it exists, otherwise it won't. Every time the
// browser loads this app, this cache will attempt to initialize itself with any data it had
// already saved to localStorage (or sessionStorage if you used that).
var myAwesomeCache = $angularCacheFactory('myAwesomeCache', {
maxAge: 900000, // Items added to this cache expire after 15 minutes.
cacheFlushInterval: 3600000, // This cache will clear itself every hour.
deleteOnExpire: 'aggressive', // Items will be deleted from this cache right when they expire.
storageMode: 'localStorage' // This cache will sync itself with `localStorage`.
});
});
Or we can inject custom Local storage implementation
storageImpl: localStoragePolyfill // angular-cache will use this polyfill instead of looking for localStorage
I am using this plugin https://github.com/grevory/angular-local-storage, which is really simple to use, while providing full API.
Also check a local storage usage for caching the templates: how to cache angularjs partials?
NOTE: This article Power up Angular's $http service with caching, and mostly the section:
Advanced caching, was for me the reason to move to angular-cache
How to create a custom Polyfill? (Adapter pattern)
As documented here, we need to pass the localStoragePolyfill implementing this interface:
interface Storage {
readonly attribute unsigned long length;
DOMString? key(unsigned long index);
getter DOMString getItem(DOMString key);
setter creator void setItem(DOMString key, DOMString value);
deleter void removeItem(DOMString key);
void clear();
};
angular-cache cares only about these three methods:
setItem
getItem
removeItem
I.e.: Implement a wrapper talking with local-storage API, transforming it to the advanced cache api. That's it. Nothing else

Resources