How to "rebuild" a $resource from a factory in angularjs? - javascript

I'm implementing my own API-Token system into my AngularJS-Laravel project, so the API-Token is sent over $http using headers. The thing is, when a user logs in, it sets the API token in the API factory, but the $resource doesn't get updated.
myApp.factory('Api', ['$resource', '$http', '$cookies',function($resource, $http, $cookies) {
var baseURL = 'an api url';
var APIToken = $cookies.token;
return {
SetToken: function(token) {
APIToken = token;
console.log(APIToken);
},
Authenticator: function(data,callback) {
$http({
url: baseURL + 'auth',
method: "GET",
params: data
}).success(callback);
},
Authors: $resource(baseURL + "journalists/:id", {id: '#id'}, {
update: {
method:'PUT',
headers: { 'API-Token': APIToken }
},
query: {
method:'GET',
isArray: true,
headers: { 'API-Token': APIToken }
}
}),
};
}]);
The most interesting part is the headers: { 'API-Token': APIToken } part. The problem is that when SetToken is called, the headers won't get updated. Is there any way around this? Am I using the wrong function for this?

Your $resource object is created and setup only once when it is called. It doesn't access the APIToken variable every time you make a call to one of its functions. In order to make the code above work, you would have to call SetToken() before you call Authors() because once you call Authors(), the $resource object is created and will use the value of APIToken at that moment. I don't know of any way to do what you want and still use the $resource service. You might have to just use the $http service directly, like you're doing for your Authenticator function.
Authors: {
update: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "PUT",
params: obj
});
},
query: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "GET",
params: obj
});
},
})
Or something like that. Hope that helps.

Related

Convert JS Post Ajax to AngularJS Post Factory

I am trying to convert an Ajax call with WSSE authentication to an AngularJS factory.
The method is Post.
The intended use of this is to access the Adobe Analytics Rest API and return data to be converted to JSON and then visualised with d3.js.
I am not familiar with the properties that can be used in an AngularJS $http post call and so not sure what is the correct way to do the WSSE auth, dataType, callback etc.
This is the original ajax code which came from a public github repo:
(function($) {
window.MarketingCloud = {
env: {},
wsse: new Wsse(),
/** Make the api request */
/* callback should follow standard jQuery request format:
* function callback(data)
*/
makeRequest: function (username, secret, method, params, endpoint, callback)
{
var headers = MarketingCloud.wsse.generateAuth(username, secret);
var url = 'https://'+endpoint+'/admin/1.4/rest/?method='+method;
$.ajax(url, {
type:'POST',
data: params,
complete: callback,
dataType: "text",
headers: {
'X-WSSE': headers['X-WSSE']
}
});
}
};
})(jQuery);
This is the current way the code is being used with pure JS:
MarketingCloud.makeRequest(username, secret, method, params, endpoint, function(response) {
data = JSON.parse(response.responseText);
});
I want to convert this to a factory and a controller respectively.
This is what I have done for the factory so far:
app.factory('mainFactory', ['$http', function($http) {
var wsse = new Wsse ();
return function(username, secret, method, params, endpoint) {
return $http({
method: 'POST',
url: 'https://' + endpoint + '/admin/1.4/rest/?method=' + method,
data: params,
headers: {
'X-WSSE': wsse.generateAuth(username, secret)['X-WSSE']
},
dataType: 'text',
});
};
}]);
And this is what I have for the controller:
app.controller('mainController', ['$scope', 'mainFactory', function($scope, mainFactory) {
mainFactory.success(function(data) {
$scope.data = data;
});
}]);
Currently I get an error saying mainFactory.success is not a function which I assume is because the factory isn't working yet.
I have resolved this question myself. The parameters I was passing to the first function in the factory were globally defined already and therefore getting over-written.
The first function is not required anyway.
Here is the factory code:
app.factory('mainFactory', ['$http', function($http) {
var wsse = new Wsse ();
return {
getAnalytics : function (){
$http({
method: 'POST',
url: 'https://' + endpoint + '/admin/1.4/rest/?method=' + method,
data: params,
headers: {
'X-WSSE': wsse.generateAuth(username, secret)['X-WSSE']
}
})
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}
};
}]);
And here is the controller code:
app.controller('mainController', ['$scope', 'mainFactory', function($scope, mainFactory) {
$scope.title = "Inn Site";
$scope.data = mainFactory.getAnalytics();
}]);

Rails + Angularjs: How to communicate (delete record from database) with backend?

I stuck on this for the whole day.
On http://localhost:3001/posts/, I list all posts I have in the database. I am trying to delete a task with using Angularjs - every loaded record from the database has a link for its deleting:
= link_to 'Delete', '', 'ng-click' => "deletePost('#{post.id}')", :id => "post_#{post.id}"
Then I have a file /assets/javascript/angular/controller/posts.js that looks like this:
var app = angular.module('AngTestApp', ['ngResource']);
app.factory('Post', function($resource) {
return $resource("/posts/:id", { id: '#id' }, {
index: { method: 'GET', isArray: true, responseType: 'json' },
show: { method: 'GET', responseType: 'json' },
update: { method: 'PUT', responseType: 'json' }
});
})
app.controller("PostsCtrl", function($scope, Post) {
$scope.posts = Post.index();
$scope.deletePost = function(index) {
console.log("index: "+index);
post = $scope.posts[index];
Post.delete(post);
$scope.posts.splice(index, 1);
console.log('aa');
}
})
When I click the delete link, I receive this error in the JS console:
DELETE http://localhost:3001/posts 404 (Not Found)
and in terminal:
Started DELETE "/posts" for 127.0.0.1 at 2015-10-15 16:23:08 -0700
ActionController::RoutingError (No route matches [DELETE] "/posts"):
The routes look like this:
resources :posts do
resources :comments
end
The JS code is very chaotic, I tried to modify a tutorial I found on the Internet, but it doesn't work well.
What is wrong in this attempt?
Thank you in advance.
You need to pass the ID of the record you're trying to delete as a parameter in the call to Rails. Rails is telling you it can't find the route because you do not have an ID.
Since you do not define the DELETE action in your factory, that is likely why the ID is not getting passed. You could also try explicitly passing the id as a param, like below:
$resource takes a params attribute, so you can modify your factory like so:
app.factory('Post', function($resource) {
return $resource("/posts/:id", { id: '#id' }, {
index: { method: 'GET', isArray: true, responseType: 'json' },
show: { method: 'GET', responseType: 'json' },
update: { method: 'PUT', responseType: 'json' },
delete: { method: 'DELETE', params: '#id', responseType: 'json' }
});
})
The $resource docs are pretty helpful: https://docs.angularjs.org/api/ngResource/service/$resource

Angular $http service / controller to JSONP

Due to my cross domain errors, I am trying to convert my $http call to a JSONP one.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:5000' is therefore not allowed
access.
I'm a beginner and having extracted my GET service from my controller, I'm struggling with finding the spot where to change $http to $http.jsonp(url) based on the Angular documentation
Here's my service.js:
.service('NCAAF',function($http, $ionicLoading) {
return {
get: function() {
$ionicLoading.show({
template: 'Loading...',
delay: 300
})
return $http (
{
method: 'GET',
cache: true,
crossDomain: true,
dataType: 'jsonp',
url: 'https://www.kimonolabs.com/api/[key]?callback=JSON_CALLBACK',
headers: {
'authorization': 'Bearer [auth]'
}
});
}
};
})
and controller.js:
.controller('NCAAFCtrl', function ($scope, NCAAF, $ionicPopup, $ionicLoading) {
var doGet = function() {
NCAAF.get().
success(function (data) {
$scope.data = data['results']['collection1'];
$ionicLoading.hide();
}).
error(function () {
$ionicLoading.hide();
var alertPopup = $ionicPopup.alert({
title: 'Something went wrong',
template: 'Try reloading in a few seconds.'
});
alertPopup.then(function() {
console.log('Fix this ish');
});
}).
finally(function() {
$scope.$broadcast('scroll.refreshComplete');
});
};
$scope.doRefresh = function() {
doGet();
};
doGet();
})
JSONP can make you do cors request ,but that doesn't mean you will be able to get correct response.
JSONP requires you to wrap your JSON response into a Javascript function call.
When you do a JSONP the request , query string will set a parameter called
'callback' that will tell your server how to wrap the JSON response.
The server should use the callback parameter from the request string to set the
response accordingly.
So the response should be
callback([ {“access_token”: “asdfsd”, “expires”: “86400" ,"type" : "bearer"}
]);
In angular it will look like
angular.callbacks._0([ {“access_token”: “asdfsd”, “expires”: “86400" ,“type” :
“bearer”} ]);
But just for your information about how to make jsonp call ,change your code
return $http (
{
method: 'GET',
cache: true,
crossDomain: true,
dataType: 'jsonp',
url: 'https://www.kimonolabs.com/api/[key]?callback=JSON_CALLBACK',
headers: {
'authorization': 'Bearer [auth]'
}
});
to
return $http.jsonp('https://www.kimonolabs.com/api/[key]?callback=JSON_CALLBACK',{
headers: {
'authorization': 'Bearer [auth]'
}
});

How to send a custom header on every request with an angular resource?

I like to send a custom header on every request with an angularjs resource. Before every request the header has to be created again. The following doesn't work. The header is calculated only once and because of this only one request works. A second request on the same resource fails. Its a lot of copy n paste of "headers: authhandler.createHeader()" also ...
myApp.service('Rest', ['$resource', 'authhandler',
function($resource, 'authhandler',{
return {
User: $resource( api_domain + "/api/users/:userid", {}, {
get: {method: 'GET', headers: authhandler.createHeader()},
remove: {method: 'DELETE', headers: authhandler.createHeader()},
edit: {method: 'PUT', headers: authhandler.createHeader()},
add: {method: 'POST', headers: authhandler.createHeader()},
patch: {method: 'PATCH', headers: authhandler.createHeader()}
}),
};
}]);
Has someone an idea how to solve this ?
I had a working solution but I don't like it because of huge amount of copy and paste source code:
myApp.controller('MyController', function(RestResource, authhandler, $routeParams) {
$http.defaults.headers.common = authhandler.createHeader();
RestResource.get({userid: $routeParams.id}, function(result) {
//...
});
});
I Would be very happy about hints how to solve this ! Thanks in advance!
You can use a request transformer:
function($resource, 'authhandler',{
return {
User: $resource( api_domain + "/api/users/:userid", {}, {
get: {
method: 'GET',
transformRequest: function(data, headersGetter) {
var currentHeaders = headersGetter();
angular.extend(currentHeaders, authhandler.createHeader());
return data;
}
},
You could also add the transformer to all requests:
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.transformRequest.push(function(data, headersGetter) {
var currentHeaders = headersGetter();
angular.extend(currentHeaders, authhandler.createHeader());
return data;
});
That way you don't have to configure anything or your resources.

Angularjs: Singleton service using $http [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
is it possible in angular to create service using $http which will take method, url, success and failure callback as parameters when called from controller.
I want to achieve following kind of functionality using angular.
var ajax = {
URL: "webservice url",
loggedIn: false,
importedId: "",
token: '',
userdetails: new Backbone.Collection.extend({}),
serverCall: function(method, data, successCallBack, failureCallBack) {
var that = this;
//console.log(method);
//console.log(successCallBack);
that.showLoading();
$.ajax({
url: that.URL + method,
method: 'post',
data: data,
// contentType:"application/json; charset=utf-8",
success: function(data) {
that.hideLoading();
if (that.checkForError(data))
{
successCallBack(data);
}
},
fail: function(data) {
that.hideLoading();
failureCallBack(data);
}
});
}
i am using https://github.com/StarterSquad/startersquad.github.com/tree/master/examples/angularjs-requirejs-2 folder structure for app and inside services i have following code
define(['./module'], function(services) {
'use strict';
services.factory('user_resources', ['$resource', '$location', function($resource, $location) {
return $resource("", {},
{
'getAll': {method: "GET", url:'JSON/myList.JSON',isArray:true}
});
}]);
});
and in controller i have following code
define(['./module'], function (controllers) {
'use strict';
controllers.controller('myListCtrl',['Phone','Phone1','loginForm','$scope','$http','user_resources','CreditCard',function(Phone,Phone1,loginForm,$scope,$http,user_resources,CreditCard){
console.log(user_resources.getAll())
}]);
});
which returns [$promise: Object, $resolved: false] how to get data from that?
A service in AngularJS is always a singleton, so you wouldn't have to do anything to achieve that. However, it seems like you do not actually want a singleton as you want to pass in different values. Thus, you might want to add your own service factory function. Something like:
function MyHTTPService($rootScope, url, method) {
this.$rootScope = $rootScope;
this.url = URL;
this.method = method;
}
MyHTTPService.prototype.serverCall = function () {
// do server call, using $http and your URL and Method
};
App.factory('MyHTTPService', function ($injector) {
return function(url, method) {
return $injector.instantiate(MyHTTPService,{ url: url, method: method });
};
});
This can be called using
new MyHTTPService("http://my.url.com", "GET");
you could also use $resource for this type of usage.
angular.module('MyApp.services').
factory('User_Resource',["$resource","$location", function ($resource,$location){
var baseUrl = $location.protocol() + "://" + $location.host() + ($location.port() && ":" + $location.port()) + "/";
return $resource(baseUrl+'rest/users/beforebar/:id',{}, {
query: { method: 'GET', isArray: true },
get: { method: 'GET' },
login: { method: 'POST', url:baseUrl+'rest/users/login'},
loginAnonymous: { method: 'POST', url:baseUrl+'rest/users/loginAnonymous'},
logout: { method: 'POST', url:baseUrl+'rest/users/logout/:id'},
register: { method: 'POST', url:baseUrl+'rest/users/register'}
});
}]);
Example of usage :
userSrv.logout = function(user,successFunction,errorFunction)
{
var userSrv = new User_Resource();
userSrv.$logout({user.id}, //params
function (data) { //success
console.log("User.logout - received");
console.log(data);
if (successFunction !=undefined)
successFunction(data);
},
function (data) { //failure
//error handling goes here
console.log("User.logout - error received");
console.log(data);
var errorMessage = "Connexion error";
if (errorFunction !=undefined)
errorFunction(errorMessage);
});
}

Categories

Resources