angular interceptor code on beforeSend not working - javascript

I am using the following code, and I looking to push the headers first, followed by the request. Using JQuery, I just add beforeSend, works fine. But i have changed over to AngularJS (which I am loving... mostly) and I get confused about interceptors!
What confuses me, is if i want to send the header first, where do I tell it, where to send the header. Looking at examples, which is not many, relating too 'beforeSend', I have either not understood, or have not seen any that fits my issue.
Code:
App.factory('postCemment', function($q,requestInterceptor, $http) {
return {
fnsend: function(sid, author, comment, callback) {
$http.Provider.interceptors.push(requestInterceptor);
$http.post("https://api.appery.io/rest/1/db/collections/comments/",
{
headers: {"Content-Type": 'application/x-www-form-urlencoded'},
params: {comment_author : author, comment : comment, statement_id : sid}
})
.success(function(commentres) {
callback(commentres);
})
}
}
})
App.factory('requestInterceptor', function() {
return {
'request': function(config) {
config.headers = {"X-Appery-Database-Id": dbid}
console.log(config);
return config;
}
}
})
App.controller('addCommentBox', function($scope, $http, $routeParams, postCemment) {
$scope.addCommentData = function() {
postCemment.fnsend($routeParams.id,$scope.aurhor,$scope.comment, function(res) {
console.log(res);
})
}
})
If I try without any type of interceptor, I just get an error that database is not specified, even though I can see it in the headers in the browser dev screen.
I have used $q and defer before, and I do read that is may be required, as some examples do not use it, but this is where the confusion is. Even with a defer, at what point do I defer?
Thanks in advance.
Andrew

Related

angular resource - $resource:badcfg

My angular throws me
Error: [$resource:badcfg] Error in resource configuration for action query. Expected response to contain an array but got an object
I have no idea why this happens. I have a db with schools, and each schools has a city property. i'm trying to get all the schools in a given city.
On the server, my controller has a function which is supposed to do exactly that:
getSchoolByData: function(req, res, next) {
School.find({city: req.params.reqCity}).exec(function (err, collection) {
if (err) {
console.log("Could not load desired school: " + err);
}
res.send(collection);
});
}
On my client side I have a resource and another controller:
resource:
app.factory('SearchSchoolResource', function($resource) {
var SearchSchoolResource = $resource('/schoolSearchResult/:reqCity', {city: 'reqCity'}, { update: {method: 'PUT', isArray: false}});
return SearchSchoolResource;
});
controller:
app.controller('SearchSchoolCtrl', function($scope, $routeParams, SearchSchoolResource) {
$scope.schools = SearchSchoolResource.query({city: $routeParams.reqCity});
});
I have no idea which one of these fails to work properly and I have no idea how to check. I'm new to angular and node, and I spent over 72 hours on this, so if someone can tell me how to fix this, it will be amazing!
Other than that I managed to return all the schools, and a single school based on given id just fine, but returning schools based on city fails.
EDIT:
If I just put the name of the city in the find function like
... find({city: 'name'}) ...
It works, but if I use req.params.reqCity it doesn't. I can't figure out why it doesn't work, it seems like req.params.reqCity is returning something different and not the given city name. Tried just using .ToArray instead of .exec and it doesn't work again. Can't figure out what the req.params.reqCity returns and still can't figure out how to fix this.
Try this way, it should work. In addition to get i am also adding other operation's syntax.
Service:
app.factory('SchoolService',function($resource){
return $resource('/schoolSearchResult/:reqCity',
{
reqCity: '#reqCity'
},
{
'update': { method:'PUT' }
},
{
'get': { method: 'GET', isArray: false }
},
{
'delete': { method: 'DELETE'}
}
);
});
controller:
app.controller('SearchSchoolCtrl', function($scope, $routeParams, SchoolService) {
var schoolService = new SchoolService();
schoolService.$get({reqCity : $routeParams.reqCity},function(result){
$scope.schools = result;
});
});

Proper use of transformers vs interceptors

When POSTing to an endpoint in a service layer to update a user's profile, I need to strip certain values from the request payload (the profile with the desired modifications from the client) and re-attach them in the response payload (the updated profile from the server). I am currently performing behavior using Angular's request and response transformers, like this:
myService.updateProfile = function (profile) {
return $http({
method: 'POST',
withCredentials: true,
url: root + 'users/profile',
data: profile,
transformRequest : requestTransformer,
transformResponse : responseTransformer
});
};
// the map used during transformation below
var myMap = {
0: 'foo',
1: 'bar',
2: 'etc'
};
// prependTransform() and appendTransform() are similar to the example provided in Angular transformer docs here:
// https://docs.angularjs.org/api/ng/service/$http#overriding-the-default-transformations-per-request
var requestTransformer = httpTransformer.prependTransform($http.defaults.transformRequest, function(profileRequest) {
profileRequest.myKey = myMap.indexOf(profileRequest.myValue);
delete profileRequest.myValue;
return profileRequest;
});
var responseTransformer = httpTransformer.appendTransform($http.defaults.transformResponse, function(profileResponse) {
profileRequest.myValue = myMap[profileRequest.myKey];
delete profileRequest.myKey;
return profileResponse;
});
I prepend a transformer to the default request transformers and append a transformer to the default response transformers. My question is, is there a better way to do this? Perhaps using interceptors, as documented here, instead? If so, how?
I think your solution is fine but if you want an alternative, you can intercept specific requests like so. HTTP interceptors are mostly useful for handling global HTTP requests/responses (auth, error handling, etc.).
In any case, the "response" payload should be taken cared of from the API/server-side.
$provide.factory('userProfileInterceptor', function() {
return {
request: function(config) {
if (config.url.indexOf('/users/profile') >=0){
if (config.params.myValue) delete config.params.myValue;
}
return config;
},
response: function(response) {
if (response.config.url.indexOf('/users/profile') >=0){
delete response.data.myKey;
}
return response;
}
};
});
$httpProvider.interceptors.push('userProfileInterceptor');

Is it possible to use angularjs cached resource method in a filter?

I have a property in the scope that has an id of external object, also I have a filter that expands this id into a full object like this:
{{ typeId | expandType }}
Filter:
.filter('expandType', ['TypeService', function (tsvc) {
return function (id) {
return tsvc.types.get({ id: id });
}
}])
where tsvc.types.get() is normal resource get method with added cache option.
.factory('TypeService', ['$resource', function ($resource) {
var typeResource = $resource('/api/types/:id', { id: '#id' }, {
get: { method: 'GET', cache: true, params: { id: '#id' } }
});
return {
types: typeResource
}
}])
As I understand angular runs additional digest after the fist one just to make sure that nothing changed. But apparently on the next digest the filter is returning a different object and I get the infdig error (digest is executed in infinite loop).
I hoped that if the resource is cached it will return the same object from cache all the time. I can confirm that there is only one trip to server while executing get() so the cache is working.
What can I do to make it work and use the filter to expand ids to full objects?
Although possible, it is usually not a good idea to bind promises to the view. In your case, filters are reevaluated on every digest, and quoting from https://docs.angularjs.org/api/ng/service/$http:
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.
Note that even if the response is served from cache, delivery of the data is asynchronous in the same way that real requests are.
To clarify, ngResource uses $http internally.
You can still use the filter calling it from your controller:
app.filter('expandType', function ($http) {
return function (id) {
return $http.get('data.json');
};
});
app.controller('MainCtrl', function ($scope, expandTypeFilter) {
var typeId = 'hello';
expandTypeFilter(typeId).success(function (data) {
$scope.expandedTypeId = data[typeId];
});
});
Plunker: http://plnkr.co/edit/BPS9IY?p=preview.
With this approach, if the only reason you were caching the response was to avoid repeated calls to the server, you can now stop caching it so that it gets fresh data later on, but that depends on your needs, of course.
I really wanted to use a filter because it was used all over the app and I didn't want to clutter my controllers. At this point the solution I came out with looks as follows:
.filter('expandType', ['TypeService', function (tsvc) {
var cache = {};
return function (id) {
if (!id) {
return '';
}
var type = cache[id];
if (!type) {
tsvc.types.get({ id: id }).$promise.then(function (data) {
cache[id] = data;
});
cache[id] = {}
return cache[id];
}
else {
return type;
}
}
}])

Angular.js Error: Expected response to contain an array but got an object although isArray is set to false

I have an angular resource factory, which returns a JSON object and looks like this:
angular.module('myApp').factory('resourceProvider', function ($resource, $http) {
return {
Attribute: $resource('http://localhost:49980/api/Attribute/:id',
{ id: '#id' }, { query: { method: 'GET', isArray: false } }),
};
});
When I 'query' the resource like this:
resourceProvider.Attribute.query(function (data) {
$scope.variable = data;
});
I get: Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an array but got an object.
This seems really strange to me because I'm setting isArray to false. Furthermore the code is working fine on other pcs. So I would be really thankful if anyone had an idea where the error could come from.
Problem solved. There was a problem with the db authenication and the error message happend to be a JSON object. So there was actually a JSON object returned instead of an array.
Question1: Why are you using angulars $resource-service and not $http-service?
Question2: If you want to use $resource, why you whant to override $resource's default behavior? See Angular Docs
And im not sure but, do you have a typo in
return {
Attribute: $resource('http://localhost:49980/api/Attribute/:id',
{ id: '#id' }, { query: { method: 'GET', isArray: false } }),
};

javascript, object, passing function as arguments with arguments- angular, jquery concept basic misunderstanding

I am trying to understand what i am really doing, since i feel i am lack of something. Could you please point me somewhere or confirm my mis/understanding?
request.then(function(response) {
updateCurrentUser(response.data.data);
currentUser.isAuthenticated();
});
Is basically this?
request = {
then : function (foo){
foo("first")
} }
request.then(function (response) { console.log(response) ; });
If you see full code here#35 and here#63
directive:
AuthenticationService.login($scope.user.email, $scope.user.password).then(function(loggedIn) {
if ( !loggedIn ) {
$scope.authError = "Login failed. Please check your credentials and try again.";
}
});
AuthenticationService as factory:
login: function(email, password) {
var request = $http.post('http://', {email: email, password: password});
return request.then(function(response) {
updateCurrentUser(response.data.data);
return currentUser.isAuthenticated();
});
},
The thing i don't understand is how come that the value of loggedIn variable is equal to the value what statement return currentUser.isAuthenticated(); returning AND NOT equal to the then(function(response) of original as i am returning promise from AuthenticationService.
And how this could be accomplished regarding to the examples above?
Thank you.
I think the problem with conception arises from the fact that you overlooked the return statement. What AuthenticationService.login does is actually a closure with predefined request, so you can imagine that login is replaced with its return value request.then(function(response) {.... Then you can simply deduce that entire code row is:
AuthenticationService.login($scope.user.email, $scope.user.password).then(
function(response)
{
updateCurrentUser(response.data.data);
return currentUser.isAuthenticated();
}).then(
function(loggedIn)
{
...
This way you may see that result from response should occur as input for the next step with login check.

Categories

Resources