Get "initially loaded" (not AJAX call) Response Headers with AngularJS - angularjs

In looking at How to read response headers in angularjs?, I see answers that involve making an http/ajax request after the page loads then getting the response headers.
I have an angularJS app that needs to render the page (immediately when it loads, not after) using some JSON in a custom response header key that I've added on my python backend.
Is there non-hacky a way to do this? Or is the very attempt at rendering a web page using AngularJS to parse response headers a hack in itself?
My headers look like this (I'm trying to get myjson) :
Keep-Alive:timeout=1, max=100
myjson:{"key2": "value2", "key1": "value1"}
Server:Apache

I think this is what you are aiming for, using $http and ngRoute. Forgive me if I'm misunderstanding. It's just loading data about this question via SO's API. If you click Load Data, you'll see the headers from SO on that page..
var app = angular.module('plunker',['ngRoute']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/home', {
template: '<h1>Test 1</h1>',
controller: 'HomeCtrl'
}).
when('/loaddata', {
templateUrl: 'load_data.html',
controller: 'LoadDataCtrl',
resolve: {
stackQuestion: function($http){
// We must return something with a promise. $http already does that, so does $resource.
// See: https://docs.angularjs.org/api/ng/service/$q
return $http({
method: 'GET',
url: 'https://api.stackexchange.com/2.2/questions/37491743?order=desc&sort=activity&site=stackoverflow'
})
}
}
}).
otherwise({
redirectTo: '/home'
})
}
]);
Then, in your controller:
app.controller('LoadDataCtrl',function(stackQuestion,$scope){
// now our data is here
$scope.question = stackQuestion.data;
$scope.headers = stackQuestion.headers();
});
http://plnkr.co/edit/ylOfSNqPAqjdg9rYxsbb?p=preview

Related

AngularJS and ui-router: wrong routes behaviour after refresh

I'm developing an application with AngujarJS and ui-router and I'm having a problem loading the routes. To facilitate the explanation I will delete parts of the code. My rotes file looks like this:
app.config(function($stateProvider, $urlRouterProvider,
$locationProvider) {
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl : 'pages/dashboard.html',
controller : 'DashController'
})
.state('dashboard.vendas', {
url: '/vendas',
templateUrl : 'pages/vendas.html',
controller : 'vendasController'
})
;
$urlRouterProvider.otherwise('/');
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
I load this route /dashboard after the user login. On this route, I load, among other things, an http method that returns the companies that the user will have access to, through the factory below:
app.factory("factoryEmpresas",
function($http,urlBase,isAuthenticated) {
return {
getEmpresas: function() {
return $http({
url: urlBase.getUrl() + '/empresas',
method: "GET",
headers: {
'X-Token': isAuthenticated.getJWT()
}
}).then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
return response;
});
}
}
});
When accessing the route /vendas (which is related to the state dashboard.vendas), I make another http call using a variable that is in the factoryEmpresas return as follows:
app.factory("factoryVendas",
function($http,urlBase,isAuthenticated) {
return {
getVendas: function(id_empresa) {
return $http({
url: urlBase.getUrl() + '/vendas?id_empresa=' + id_empresa,
method: "GET",
headers: {
'X-Token': isAuthenticated.getJWT()
}
}).then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
return response;
});
}
}
});
Everything works perfectly, until the user decides to refresh (F5) when on the route /vendas. At that moment the loading of the two routes /dashboad and /vendas is triggered. However, when making the http call at factoryVendas, the factoryDashboard has not yet returned the getEmpresas function. Thus, the variable "empresa_id" is not filled with the value that it should, thus resulting in an undefined call in place of "empresa_id".
The question I ask is, how can I make factorySales wait for the factoryDashboard to return so that I can make the call with the variable duly filled in?
Any help will be welcome.
Thank you!
It sounds like vendas has a direct dependency on empresa. Would it make sense to make empresaId part of the route parameters for accessing vendas? That way the information needed to load the page would always be accessible (from $stateParams), even on reload
.state('dashboard.vendas', {
url: '/:empresaId/vendas/',
templateUrl : 'pages/vendas.html',
controller : 'vendasController'
});
The other thing you could do is define load order by creating a resolve on the parent that the child consumes. Then uirouter knows it needs to wait for the parent resolve before attempting to load the child.
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl : 'pages/dashboard.html',
controller : 'DashController',
resolve: {
Empresas: function(factoryEmpresas) {
return factoryEmpresas.getEmpresas();
}
}
})
.state('dashboard.vendas', {
url: '/vendas',
templateUrl : 'pages/vendas.html',
controller : 'vendasController',
resolve: {
Vendas: function(Empresas, factoryVendas) {
var id_empresa = Empresas[0].id; // just kind of guessing here
return factoryVendas.getVendas(id_empresa);
}
}
})
Vendas and Empresas can be injected into their respective controllers.
While this would work I'd actually discourage this method because now your user is waiting around more for content to appear. Studies have shown its better to show your users incremental progress, your app will feel faster. I try to avoid resolves when possible and have initialization logic in my controller. That way, the page loads immediately and fills in as data becomes available.

Gettting the received Http Headers in Angular JS ui-router

I am a newbie for Angular.
I am having the following Angular JS(v.1.7) ui-router
.state('helpPage', {
url: "/help",
data: {
roles: []
},
views: {
helpDoc: {
templateUrl: 'app/modules/help/help.tpl.html',
controller: 'helpCtrl'
}
}
})
When the User hits this page I want to retrieve the Headers.
Can I get them in the Controller or in the ui-route's resolve method itself ?
Tried HttpInterceptor but it is not helping out.
Any help is much appreciated.
Use the headers property of the $http response object:
$http.head(url).then(function(response) {
var headerGetter = response.headers;
console.log(headerGetter("headerName"));
});
For more information, see
AngularJS $http Service API Reference - $http.head

Unable to retrieve the error associated and display in login page

Using AngularJS and Spring Security, when the authentication fails there is a redirect to the login page with error=true. I need to display this error on login page (AngularJS). I don't know how to do this.
Below is the declaration of authentication-failure-url in ssecurity-context.xml:
<security:form-login login-page="/login"
login-processing-url="/authenticate"
authentication-failure-url="/login?error=true"
username-parameter="username" password-parameter="password"/>
Could some please tell me how to retrieve the error and show on login page?
JS
angular.module('app.services')
.service('AuthenticateService'‌​,['$http','$location‌​',function($http,$lo‌​cation)
{
return
{
login : function(uname, pword)
{
var data = "username="+uname+"&password="+pword;
return $http.post("authenticate",data,
{
headers: { "Content-Type": "application/x-www-form-urlencoded" } })
.then(function (response)
{
console.log(response.status);
},function(error)
{
console.log(error.status);
});
}
}
}]);
When your login attempt fails, you're redirecting to /login/error/true
Then, you should have on your angularJS a route to that URL with the partial HTML that you want to display, alongside with an angularJS controller which will handle or do the appropriate actions upon that URL.
For example, let's say that your route file will look this:
var myApp = angular.module("myApp", [ "ngRoute" ]);
myApp.config(function ($routeProvider) {
$routeProvider
.when("/login/error/:errValue",
{controller: "LoginController", templateUrl: "/partials/login.html"})
});
Now all you have to do is tho check on LoginController whether :errValue is true or false. and act upon that value.
with wrong credentials, I tried checking the value of errValue in the controller, but its says undefined
Below are the routes declared
$stateProvider
.state("/login",{ //this for login page
url:'/login',
templateUrl:'./resources/js/baseapp/ContactLogin/views/contactLogin.html',
controller:'contactLoginCtrl'
})
.state("/home",{
url:'/home', // this is for home page
templateUrl:'./resources/js/baseapp/ContactHome/views/ContactHome.html',
controller:'contactHomeCtrl'
})
.state("/login:error/:errValue",{ // this is for login error page
url:'/home',
templateUrl:'./resources/js/baseapp/ContactLogin/views/contactLogin.html',
controller:'contactLoginCtrl'
})
$urlRouterProvider.otherwise("/login");

Integrating AngularJS with Play framework

I have in my javascript the following AngularJS snippet:
$http({
method: 'POST',
url: '/checklogin'
})
.then(function successCallback(response) {
alert('It worked');
}, function errorCallback(response) {
alert('Error:' + response.status)
});
That points in the routes file to a Play Controller:
POST /checklogin controllers.CheckLogin.index
The problem is that for each different Angular HTTP post I need to create an entry in routes (around 200 entries to create and maintain). Is there a way to avoid that?
You can use dynamic matching in routes and match your route somewhere in your application, but it isn't elegant solution.
GET /*yourRoute AppController.matcher(yourRoute)

How to specify headers parameter for custom Angular $resource action

The following works fine, but I am thinking this modifies the $httpProvider globally, which isn't what I want.
angular.module('SessionService', ['ngResource'])
.config(function($httpProvider){
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
})
.factory('Login', function($resource){
var resource = $resource('/adminui/login',{},{
post:{
method:"POST",
isArray:false
},
});
return resource;
})
LoginCtrl = function($scope,Login) {
$scope.login = function(){
Login.post($.param({user:$scope.user.username,password:$scope.user.password}),$.noop,$.noop)
}
}
Is there anyway to do this instead?
...
.factory('Login', function($resource){
var resource = $resource('/adminui/login',{},{
post:{
method:"POST",
isArray:false,
headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'} // ignored
},
});
return resource;
})
The "headers" parameter seems to be ignored. the request is still
Content-Type:application/json;charset=UTF-8
Is my value for headers ok?
I have confirmed that 1.1.3 does indeed support this. However, you need to make sure you also get the 1.1.3 version of the resource service. A quick test of:
angular.module('myApp', ['ngResource']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {templateUrl: 'partials/partial1.html',controller: 'MyController'});
$routeProvider.otherwise({redirectTo: '/'});
}])
.controller("MyController", function( $scope, Bug) {
Bug.post({test:"test"});
})
.factory('Bug', function($resource){
var resource = $resource('/bug',{},{
post:{
method:"POST",
isArray:false,
headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}
},
});
return resource;
});
This will make a request with the headers set to (confirmed using Chrome):
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
A quick note, I was unable to find a download of the angular-resource.js, so I had to go the the github website to download it. It is here.
For some giggles, I created a fiddle. Notice that there will be a failed POST call, but its headers are set correctly. Example Fiddle
While the development docs (as of 12 Oct) show that overriding headers is possible in a $resource, it hasn't yet been released (v1.0.2 or v1.1.0). The feature is in the v1.0.x and master branches, however. In order to get at that feature, you might consider building from the v1.0.x branch for now.
How to build: http://docs.angularjs.org/#H1_4
Alternatively, you could pull from the snapshot build: http://code.angularjs.org/snapshot/
Looks like this feature will be in the next release.
Just adding the link to the 1.1.5 resource files (and others): http://code.angularjs.org/1.1.5/
You can set the URL to match the version you are looking for.
e.g. 1.1.4: http://code.angularjs.org/1.1.4/

Resources