Angularjs: maintain http body after redirect - javascript

Hi everybody and sorry for the English (if you found some mistakes),
I have the next question: I am in the page A and I call a web service that returns a JSON in the body, after this I redirect to another page B.
My question: after the redirection, body is kept ? In oder words, can I get or access to the body (if the body contains the JSON)?
Example
The web service:
app.service('LoginService', ['$http', function($http) {
this.retrieveUser = function(username, password) {
var url = app.baseURI + username+"/"+password;
return $http.get(url);
};
...
JS redirect
self.login = function(username, password){
LoginService.retrieveUser(username, password)
.success(function (data) {
if(data.usuario.rol == "G")
window.location.href="http://localhost:8080/Natureadventure/html/gerente/gestionarActividades.html";
}).error(function(data){
$scope.loginForm.password.$setValidity("password", false);
});
};
Thanks!

Angular is completely client-sided, so, aside from setting something in localStorage, cookies or sessionStorage, no, you will not be able to do this.
The way around it is to turn your Angular application into a single-page application; you never really change the page of the website as such, but Angular can emulate the changing of your web page (i.e the content and the layout) through a library like ui-router or ngRoute.
The downside to this is that if you are either stuck with ugly hashbang URLs or you enable html5Mode, which breaks if you refresh the page. The way to fix that is to either a) stick with hashbang URLs or b) make your server redirect any unknown request to your index.html and let angular do the routing for you.

Related

Race condition when fetching request.url in Node / Express

I have a Node webapp which supports URLs in multiple languages. I have some middleware to generate a Welsh version of the current URL (eg. for the URL /foo, the Welsh version would be /welsh/foo), which is presented on-page as a link.
This function takes a request object and returns the updated URL (accessed via request.url). Unfortunately, when I open several pages at once on my site, some pages get the wrong URL in the <a> link (eg. they get the Welsh URL for one of the other pages I've opened). If I reload the page, the link is re-generated, this time correctly.
My middleware looks like this:
res.locals.getCurrentUrl = (req, locale) => {
// snip: some logic to check if the URL already contains the locale
return "://" + req.get('host') + req.originalUrl;
};
... then I call it in templates like getCurrentUrl(request, 'welsh').
I only see this behaviour when I open a dozen tabs at once (via JavaScript – I have a status page with a button that opens a bunch of site URLs at once). Obviously this isn't a real-life use case, but at moments of high traffic, this race condition might kick in.
Is there a better, more reliable way here to associate per-request variables like url with the rendered output? Am I doing something wrong?
Fixed this by making the request object available to my templates in a middleware function (beforehand I set it as a global on the template engine which clearly introduced this race condition):
app.use(path, (req, res, next) => {
res.locals.request = req;
return next();
});
It might be that you're using a Lambda function, and those retain the outer scope.
Try
res.locals.getCurrentUrl = function() {...}
instead.

AngularJs bookmarkable url and query parameters

I'm trying to fix one mistake which one of the previous developer has did. Currently in project we have half-bookmarkable pages. Why half? Because if token has expired user will be redirect to resourse where he has to provide his credentials and on success he will be redirect to previous resource which he has used before. Sounds good for now. The problem here is next, some of resources have server side filtering and highly complicated logic which comes in the end to the one object like this:
param = {
limit: 10,
offset: 0,
orderBy: 'value',
query: 'string query can include 10 more filters'
};
then thru the service it sends a request to the end point
var custom = {};
function data(param) {
custom.params = param;
return $http.get('/data_endpoint', custom)
.then(function (response) {
return response.data;
});
From this part request works fine and response is correct but url isn't. User cannot store current url with search params because url doesn't have it and if user will try to get back to previous page with applied filters he won't be able to do that.
Also there is interceptor in this application, which add one more query param to every api request, because every api request requires some specific validation. This param is always the same.
I have tried to add $location.search(param) exactly to this data service but it breaks the app with infinity loop of login / logout looping, because interceptor stops working and all other request are sending without special query param
Then I thought to add this params inside interceptor like this:
config.params.hasOwnProperty('query') ? $location.search(config.params) : $location.search();
But it still breaks app to infinity loop.
This method adds query to url but doesn't allow to modify it, so if user applied additional filtering, it doesn't send new modified request but sends old one.
if (config.params.hasOwnProperty('query')){
for (var key in config.params){
$location.search(key, config.params[key])
}
}
That's why I decided to ask question here, probably somebody gives an advice how to solve this problem. Thanks in advance.

Calling the app config method inside ajax response - AngularJS

I am developing an app using angularjs and this is my first hands on using angular. Although, I have started understanding it and have developed some part of the app but I am stuck at one particular point.
I am trying to implement login functionality, so as the page loads, I am authenticating user and redirecting him to login page. On successful login, I am storing some values of user in one of the config provider.
Now I am using an API which has their own method of authentication and they have expose the ajax method which I can use to authenticate a user.
I have provided a snippet below. What I am primarily doing is using the external API, authenticating the user and once authenticated, I am getting roles associated to that user using another ajax method of the API, called "GetUserDetails".
And inside the response of the "GetUserDetails", I am injecting a provider and setting some values, so I can use this across my app.
The problem here is the app.config method is never called/executded. I mean the ajax request is returning response, and the alert is displayed on my page, but app.config is never executed.
But the same app.config if I call inside the done() of GetUser method, the app.config gets executed and stores values in my provider. But I want the GetuserDetails values also to be stored before I do anything in my app as I want to execute certain functionality based on user.
Below is my function in main.js file
function(angular,angularRoute,app,routes,configService){
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
$.c.authentication.getUser()
.done(function(response){
if(response.userName!="anonymous"){
$.c.ajax({
method: "GetUserDetails",
parameters: {
User: response.user
}
})
.done(function(res) {
alert("I have reached the destination").
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(true);
configServiceProvider.setUserName(response.userName);
configServiceProvider.setUserObject(response);
configServiceProvider.setUserRoleDetails(res);
}]);
})
.fail(function(res) {
alert("Error while getting user roles ."+res);
});
angular.resumeBootstrap([app['name']]);
}
else
{
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(false);
configServiceProvider.setUserName(response.userName);
}]);
//Show Login Screen
var url = window.location.href.split("#")[0];
window.location.href = url + "#/Login";
angular.resumeBootstrap([app['name']]);
}
})
.fail(function(response){
$rootScope.isLoggedIn=false;
});
});
Here is my configServiceProvider
define(['../app'],function(app){
return app.provider('configService', function(){
var options={};
this.setLoginStatus = function(status){
//$rootScope.isLoggedIn = status;
options.isLoggedIn=status;
};
this.setPreLoginInfo=function(info){
options.preLoginInfo=info;
};
this.setUserName=function(name){
options.username=name;
}
this.setUserObject = function(userObject) {
options.userObject = userObject;
}
this.setUserRoleDetails = function(userRoleDetails) {
options.userRoleDetails = userRoleDetails;
}
this.$get=[function(){
if(!options){
}
return options;
}];
});
})
Can anyone please explain me what's going wrong here or what I am missing ?
Also, is there any alternative to achieve the same functionality ?
No luck in figuring out why the above scenario was not working. Since I had already spent lot of time behind this, I have found a workaround to achieve the same with the use of services.

The ui-router for angular seems to be cacheing the resolve. When I don't want it to

The Background:
I am using ui-router for my Angular page routing needs. It's working great so far, however I'm running into an issue. When I load a state and I resolve my user object. I use restangular to make the call to the database and it returns a promise. Everything works great. If I then log out, and log in as another user. Then navigate back to that same page it shows the previous user object.
Things that I've discovered:
The rest api call is being made every time when the state loads, and
it is the correct information.
If I place a break point inside my controller the user object that the resolve passes is the cached
information.
Theories:
The rest API end point is /users/me/, which is the same end point for
every user. We just deliver different information based off of the
JWT token we pass. Somewhere must things since it's the same call
don't bother delivering the goods it already got.
Things I've tried:
I've confirmed that the API call isn't cached, and it is delivering
the correct information to angular
I've tried grabbing the
$cacheFactory of $http and .removeAll.
Sample code:
angular.module('services.user', [ ])
.factory('User', function(Restangular) {
return Restangular.service('users');
});
angular.module('settings.profile', [
'ui.router',
'services.user'
])
.config(function($stateProvider){
$stateProvider
.state('settings.profile',{
url: '/profile',
templateUrl: 'app/settings/profile/settings.profile.html',
controller: 'SettingsProfileCtrl',
authenticate: true,
resolve: {
user: function(User) {
var user = User.one('me').get()
return user;
}
}
});
})
.controller('SettingsProfileCtrl',
function($scope, $location, user, $http, apiUrl){
$scope.user = user;
}
I had the same problem, however in my case the data requested in the resolve property wasn't coming from an API so HTTP caching definitely wasn't the problem.
I added {reload: true} for the options property in the troublesome $state.go call and this seems to have forced ui-router to refresh the resolve property. I no longer get the previous user's roles and permissions, which is nice :)
Your REST API parameter does not change i.e. it stays the same /users/me/ in all the requests. While the browser may not cache - which is why you see different correct information the cache.
You can try configuring Restangular to validate the theory by doing as below:-
RestangularProvider.setDefaultHttpFields({cache: true});
However I advise you to use URLs and REST API in the spirit of REST style i.e. use something like...
/users/me/username
where username changes based on the user OR if you have some constraints do the following
/users/me/?t=timestamp
Try adding cache: false to the state configuration object. But I also recommend adding a different parameter to the requests like userId for example.

Facebook auth.sessionChange event and page changes

I am creating a Facebook Canvas application, and I am following more or less the demo app.
As in the demo, I can get the user data from the signed_request which is POSTed to my site on the first page load. Moreover, as suggested in the demo, I use the following snippet to reload the page on user changes:
var Config;
function facebookInit(config) {
Config = config;
FB.init({...});
FB.Event.subscribe('auth.sessionChange', handleSessionChange);
...
}
function handleSessionChange(response) {
if ((Config.userIdOnServer && !response.session) ||
Config.userIdOnServer != response.session.uid) {
goHome();
}
}
function goHome() {
top.location = 'http://apps.facebook.com/' + Config.canvasName + '/';
}
Here Config is an object which is populated with info from the server.
The problem appears when the user navigates the application using a link. If I use AJAX, the page is not actually reloaded and everything works fine. But if I use a standard link, the user comes to another page of my application with a standard GET request. In this case, I do not know how to get the info about the user, so Config.userIdOnServer is undefined and a page reload is triggered.
Of course I can avoid this by removing the call to handleSessionChange, or by making a one-page app with only AJAX links, but I feel I am missing something basic about the Facebook flow.
My fault, I had problems in retrieving the cookie with the user identity for subsequent requests.

Categories