I have multiple factories in my angular service located in different js file. And there is common base of all the queries:
1) Authorization: Bearer token (header) (required after login)
2) AccessDateTime, UserIPAddress (required before login)
3) AccessDateTime, UserIPAddress, UserID (required after login)
Now, I find that it is very tedious to repeat this on each of the resource. How could i make a base for this? I thought that this is something very common but i could not found any documentation on this. Something like jquery.AjaxSetup().
Default Code
angular.module('app.test').factory('Test', ['$resource',
function($resource) {
return {
resource1: $resource(
url: 'test1/:testId/:AccessDateTime/:UserIPAddress',
headers: { Authorization: Bearer token},
params: { testId: '#_id', AccessDateTime:'#AccessDateTime', UserIPAddress: '#UserIPAddress' }
}),
resource2: return $resource(
url: 'test2/:testId/:AccessDateTime',
params: { testId: '#_id', AccessDateTime:'#AccessDateTime' }
});
}
}
]);
Code after base resource implemented(Illustration only)
angular.module('app.base').factory('FactoryBase'), ['resource',
function($resource) {}
if (resource need authorization) {
auto append header, AccessDateTime, UserIPAddress
} else if (resource do not need authorization) {
auto append AccessDateTime
}
// depending on attribute set with authorize: true/false
}
]);
angular.module('app.test').factory('Test', ['$resource',
function($resource) {
require('FactoryBase'),
return {
resource1: $resource(
url: 'test1/:testId',
authorize: true
}),
resource2: $resource(
url: 'test2/:testId',
authorize: false
}),
}
]);
Put modifier functions in your factory:
angular.module('app.test').factory('Test', ['$resource',
function($resource) {
var defaultConfig1 = {
url: 'test1/:testId/:AccessDateTime/:UserIPAddress',
headers: { Authorization: Bearer token},
params: { testId: '#_id',
AccessDateTime:'#AccessDateTime',
UserIPAddress: '#UserIPAddress'
}
};
var defaultConfig2 = {
url: 'test2/:testId/:AccessDateTime',
params: { testId: '#_id',
AccessDateTime:'#AccessDateTime'
}
};
function mod1(arg) {
var obj = defaultConfig1;
//modify config
return obj;
};
function mod2(arg) {
//modify and return defaultConfig
};
return {
resource1: $resource(defaultConfig1),
resource2: $resource(defaultConfig2).
modified1: function (arg) {
return $resource(mod1(arg));
},
modified2: function (arg) {
return $resource(mod2(arg));
}
}
}
]);
You have the full power of JavaScript to modify the configuration objects as you please before returning them.
Related
In my angular app, I want to use angular custom header. I'm using the following code::
Angular Factory
angular.module('app').factory('UserAPI', ['$resource', 'session', function($resource, session) {
var mainUrl = 'http://localhost:8006/dev' + '/users';
return {
getService : function() {
var token = session.getToken();
console.log(token); //token is printed here
return $resource(mainUrl, { }, {
getData: {
method: 'GET',
url: mainUrl + '/:userId/dashboard',
isArray: true,
headers: { 'Token': token }
}
});
}
}
}]);
Angular Controller
angular.module('app').controller('UserCtrl', ['$scope', 'UserAPI', function($scope, UserAPI) {
var user = UserAPI.getService();
user.getData({ userId: 'some-user-id' }, {}, function(res) {
}, function(err) {
});
}]);
When I make call user.getUser(......), an url is generated as like as GET:: http://localhost:8006/dev/user/some-user-id/dashboard instead of GET:: http://localhost:8006/dev/user/some-user-id/dashboard?token=SomeVeryLongToken, I mean token is missing on api call, although I'm using headers: { 'Token': token } but still problem.
How can I solve this problem?
NB "angular": "^1.4.0",
"angular-resource": "^1.4.0",
change headers: { 'Token': token } to params: { 'token': token }
You're adding token as a request header, not as a property in the query string. Use the second (in your example empty) object to add parameters, or add them directly in your controller:
user.getUser({token: 'sometoken'}, {}, function(res) {
}, function(err) {
});
I am trying to make an update to an existing object but get the following error $scope.entry.update is not a function.
I created a service called 'budgetResource'
"use strict";
angular.module("common.services").factory("budgetResource", ["$resource", "appSettings", budgetResource])
function budgetResource($resource, appSettings) {
return $resource(appSettings.serverPath + "api/budget/:id", null,
{
'update': { method: 'PUT', isArray: true },
'delete': { method: 'DELETE', isArray: true },
'save': { method: 'POST', isArray: true }
});
}
Herewith the function in my controller where budgetResource service is injected with the function $scope.updateBudgetAmount being called.
$scope.updateBudgetAmount = function (categoryId) {
$scope.entry = new budgetResource();
$scope.entry = {
"budgetAmount": $scope.budgetAmount,
"categoryId": categoryId
}
$scope.entry.update({ id: categoryId },
function (data) {
$scope.categories = data;
$scope.category = "";
},
function (error) {
$scope.message = error.statusText;
});
}
which in turn calls the webapi method
public IHttpActionResult Put(int id, [FromBody]Category cat)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
BudgetRepository repo = new BudgetRepository();
var categories = repo.SaveCategory(cat);
return Ok(categories);
}
How can modify this so that it is dine correctly?
After you do $scope.entry = {...},$scope.entry becomes a plain javascript object, so $scope.entry.update is not exist.
I'm trying to pass parameter to WebAPI, but something doesn't work. Not sure if I should add :id to the $resource path or not?
My service:
dataService.factory('Widgets', ['$resource', function ($resource) {
var data = $resource('/api/:path', {
path: '#path'
}, {
getWidgets: {
params: { path: 'widgets' },
method: "GET",
isArray: true
},
getWidget: {
params: { path: 'widgets' },
method: "GET",
isArray: true
},
getCategories: {
params: { path: 'widgetCategories' },
method: "GET",
isArray: true
},
});
return data;
}]);
In the controller:
Widgets.getWidget({ id: $rootScope.widgetId }).$promise.then(function (result) {
$scope.widget = result;
});
In ASP.Net Controller:
[HttpGet]
public IEnumerable<Widget> Get()
{
return _dbContext.Widgets;
}
[Route("api/[controller]/{id}")]
[HttpGet]
public Widget Get(int id)
{
return _dbContext.Widgets.Where(w => w.Id == id).FirstOrDefault(); ;
}
Could someone have a look please?
I want the user to be able to set the slug name (URL) for a document in my app, but also I need some control so users don't override each other. It needs to be a separate call (not integrated with create/update) so the user can get visual feedback on their own slug name suggestions.
Therefore I've created a suggestSlug API call that takes an optional slug parameter as seed for the final slug name.
This is what my Express routes looks like:
app.get('/api/projects/suggestSlug/:slug', projects.suggestSlug);
app.get('/api/projects/suggestSlug', projects.suggestSlug);
app.get('/api/projects', projects.list);
app.get('/api/projects/:id', projects.show);
Now, I want to extend ngResource on the client side (AngularJS) to make use of this API:
angular.module('myapp.common').factory("projectModel", function ($resource) {
return $resource(
"/api/projects/:id",
{ id: "#id" },
{
update: { method: "PUT", params: { id: '#_id' } },
del: { method: "DELETE", params: { id: '#_id' } }
}
);
});
How do I extend the ngResource client to use my new API?
This was my solution: adding a separate $http-based method to my projectModel:
angular.module('myapp.common').factory("projectModel", function ($resource, $http) {
var projectModel = $resource(
"/api/projects/:id",
{ id: "#id" },
{
update: { method: "PUT", params: { id: '#_id' } },
del: { method: "DELETE", params: { id: '#_id' } }
}
);
projectModel.suggestSlug = function (slugSuggestion, callback) {
$http.get(
'/api/projects/suggestSlug/' + slugSuggestion
).success(callback).error(function(error) {
console.log('suggestSlug error:', error);
});
};
return projectModel;
});
Ok, so I have this service that is dependent on another service value that the user can change in the app interface. Something like this:
app.service('Applications', ['$resource', 'URL',
function ($resource, URL) {
var applicationsResource = $resource(URL + '/applications/:id', { id: '#id' }, {
query: {
method: 'GET',
isArray: true,
transformResponse: function(body, header) {
var response = angular.fromJson(body);
return response.data.applications;
}
}
});
var applications = applicationsResource.query(function() {
applications.current = applications[0];
});
return applications;
}
]);
app.service('Users', ['$resource', 'URL', 'Applications',
function ($resource, URL, Applications) {
return $resource(URL + '/users/:id', { id: '#id' }, {
query: {
method: 'GET',
isArray: true,
headers: {
'User': Applications.current.username,
'Pass': Applications.current.password
},
transformResponse: function(body, header) {
var response = angular.fromJson(body);
return response.data.users;
}
}
});
}
]);
Example of working controller code:
app.controller('usersController', ['$scope', '$resource', 'URL', 'Applications',
function ($scope, $resource, URL, Applications) {
$scope.users = [];
$scope.reload = function() {
$scope.loading = true;
var usersResource = $resource(URL + '/users/:id', { id: '#id' }, {
query: {
method: 'GET',
isArray: true,
headers: {
'User': Applications.current.username,
'Pass': Applications.current.password
},
transformResponse: function(body, header) {
var response = angular.fromJson(body);
return response.data.users;
}
}
});
$scope.users = usersResource.query(function() {
$scope.loading = false;
});
/*
// after injecting Users, this is what I want to do, instead of what's above
$scope.users = Users.query(function() {
$scope.userTable.reload();
$scope.loading = false;
});
*/
};
$scope.$watch('Applications.current', function (newApplication, oldApplication, scope) {
if (newApplication && newApplication !== oldApplication) {
scope.reload();
}
});
}
]);
I want to replace that usersResource with my Users service, but that's where I'm stuck now.
The issue is that no matter what I do, the Applications.current on the Users service is always null. (I only make use of this service after making sure that Applications.current is not null on the controller)
If I move the resource directly to the controller, it works, but I want to move these away from the controllers.
Any tips on how to fix or improve this?
You should know that $resource is async and you call Users service before actually you got response from server and populated applications.current. This a reason why Applications.current is null into Users service.
In your case I would use Uses service into Applications:
app.service('Applications', ['$resource', 'URL', 'Users',
function ($resource, URL, Users) {
var applicationsResource = $resource(URL + '/applications/:id', { id: '#id' }, {
query: {
method: 'GET',
isArray: true,
transformResponse: function(body, header) {
var response = angular.fromJson(body);
return response.data.applications;
}
}
});
var applications = applicationsResource.query(function() {
applications.current = applications[0];
// call the Users
Users.query(applications.current) /**/
return /* ... */;
});
return applications;
}
]);