I'm trying to save a object with ngResource this way:
var Tasks = $resource("http://example.com/task", {
task: {
id: '#id'
}
}, {
'save': {
method: 'POST',
params: {
key: "abc"
}
}
});
var task = new Tasks();
task.id = "123";
task.$save();
This is generating this URL:
http://example.com/task?task=%7B%22id%22:%22#id%22%7D&key=abc
Why is the "#id" string not getting replaced with the actual data? Why is the key parameter not showing up?
I would highly suggest you modify the api to not pass json strings, but if you absolutely have to you can do something like the following
var Tasks = $resource("http://example.com/task", {
task: '#json'
}, {
'save': {
method: 'POST',
params: {
key: "abc"
}
}
});
var task = new Tasks();
task.id = '123';
task.json = angular.toJson(task);
Related
I have an object like this:
var user= {
name:"test",
lastname: "test1"
year: "52"
}
and array of files:
var files= [];
files.push(
$scope.file1,
$scope.file2,
$scope.file3,
);
I'm triying upload the array file and the json data with this code:
$http({
url: '/Create/User',
method: 'POST',
data: {model: angular.toJson(user), files: files}, // {model: user, files: files}
headers: { 'Content-Type': undefined },
transformRequest: function(data) {
var formData = new FormData();
formData.append("model", data.model);
for (var i = 0; i < data.files.length; i++) {
formData.append("files[" + i + "]", data.files[i]);
}
return formData;
},
})
When I send the data, I just get the files but the value in the model is null, what I'm doing wrong?
[HttpPost]
public ActionResult User(UserVM model, HttpPostedFileBase[] files)
{
return Json(new { success = true });
}
I'm using angular version 1.5.7. Thanks for any help.
I am new to Angular and having hard time to understand how to get the value from a resolved promise. I used $q.all([element1.$promise, e2.$promise]). I got the element1 which is a json object. For, element2 which is a scalar containing 2.0. I tried element[1] just like element[0] but it contains no property, so I don't know how to get the value. I tried .val, .data, etc. I know both the web api and angular are getting 2.0.
resolve: {
accountResource: "accountResource",
account: function(accountResource, $stateParams, $q) {
var info = accountResource.get({ accountId: $stateParams.accountId });
var currentBalance = accountResource.getCurrentBalance({ accountId: $stateParams.accountId });
return $q.all([info.$promise, currentBalance.$promise]);
}
vm.account = account[0];
vm.currentBalance = account[1];
resource function
function accountResource($resource) {
var webApiUrl = "https://localhost:44301";
return $resource(webApiUrl + '/api/account/:accountId', {}, {
get: {
method: 'GET'
},
query: {
method: 'GET',
isArray: true,
url: webApiUrl + '/api/account/search/:queryMethod/:queryString'
},
getCurrentBalance: {
method: 'GET',
url: webApiUrl + '/api/account/getcurrentbalance/:accountId'
}
});
}
You can call $q.all likes this (with dictionary instead of array):
return $q.all({info: info.$promise, currentBalance: currentBalance.$promise})
And after that get information in this way:
vm.account = account.info;
vm.currentBalance = account.currentBalance;
Try to rewrite your resource as this:
function accountResource($resource) {
var webApiUrl = "https://localhost:44301";
// Add second parameter {accountId: "#accountId"}
return $resource(webApiUrl + '/api/account/:accountId', {accountId: "#accountId"}, {
get: {
method: 'GET'
},
query: {
method: 'GET',
isArray: true,
url: webApiUrl + '/api/account/search/:queryMethod/:queryString'
},
getCurrentBalance: {
method: 'GET',
url: webApiUrl + '/api/account/getcurrentbalance/:accountId'
}
});
}
Updated
You can add transformResponse property to your getCurrentBalance function in accountResoure. And transform your value from API to json format.
getCurrentBalance: {
method: 'GET',
url: webApiUrl + '/api/account/getcurrentbalance/:accountId',
transformResponse: function (balanceFromApi) {
return { balance: balanceFromApi };
}
}
And finally you can get information, likes this:
vm.account = account.info;
vm.currentBalance = account.balance;
I tested it with $httpBackend service and everything is fine now. Hope this helps.
i have
$http({
url: 'http://webapi.-----UA_WebApi/GetUserAccount',
method: 'POST',
params: {Username:Username, Password:Password},
headers: { 'Content-Type': 'application/json;charset=utf-8' },
})
and in my service i wrote this method :
PostLogin: function (apiName, params) {
var fullParams = getFullParams(apiName, params);
var promise = $resource(buildUrl(apiName), {}, POST).get(fullParams).$promise;
updateAllowedFilters(promise);
return promise;
}
if anyone could help me understand what i am doing (right and wrong) pls ?
i would also like an example in how to use the angular resource for post.
the PostLogin works
PostLogin: function (apiName, params) {
var fullParams = getFullParams(apiName, params);
var promise = $resource(buildUrl(apiName), {}, POST).get(fullParams).$promise;
updateAllowedFilters(promise);
return promise;
}
.then(function (results) {
if(results.data.TotalRows==1) {}
TotalRows is undefined when debugging. but there is TotalRows in the api
thanks
var actions = {
post: {
method: 'post',
transformResponse: function(data) {
// here is your chance to change received data
return new Model(angular.fromJson(data));
}
}
};
var url = "http://postSomeData/:id/somethingElse/:name";
var parameters = { id : 1, name : "test" }
var data = { name : "test", type : "some type" };
return $resource(url, parameters, actions).post(data).$promise;
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;
});
I have few resources written on AngularJS that access a Tastypie API. Everything works fine, except for a detail: tastypie always encapsulate the actual result inside a objects attribute on a JSON, example:
/api/v1/reminder/:
{
meta: {
limit: 20,
next: null,
offset: 0,
previous: null,
total_count: 3
},
objects: [{
category: {
color: "#999999",
id: 1,
name: "Groceries",
resource_uri: "/api/v1/category/1"
},
description: "",
due_date: "2010-10-16",
id: 1,
repeat: "weekly",
resource_uri: "/api/v1/reminder/1",
value: "-50"
}, {
category: {
color: "#999999",
id: 1,
name: "Groceries",
resource_uri: "/api/v1/category/1"
},
description: "",
due_date: "2010-10-17",
id: 2,
repeat: "weekly",
resource_uri: "/api/v1/reminder/2",
value: "-50"
}
}
It was wasy to fix using a callback to the get() call:
Reminder.get().$then(function (result) {
$scope.reminders = result.data.objects;
});
But I know result.resource is an actual Reminder instance.
.factory('Reminder', ['$resource', function($resource){
var Reminder = $resource('/api/v1/reminder/:id', {}, {
get: {
method: 'GET',
isArray: false
}
});
Reminder.prototype.TESTE = function () {console.log('asd');};
return Reminder;
}])
Now I need to implement behavior on my Reminder class, and I need every element on my meta.objects to be an instance of Reminder:
Reminder.get().$then(function (result) {
$scope.reminders = result.data.objects;
result.resource.TESTE(); // -> outputs 'asd'
o = result.data.objects[0];
o.TESTE // -> undefined, obvisously
i = new Reminder(o);
i.TESTE() // -> outputs 'asd'
});
So, how to I get angularjs to understand that every object on objects is the actual result so it behaves like a list of instances?
The workaround is to creating a new list iterating on the results creating the instances, but it's not optimal...
Suggestions?
Solution by #rtcherry:
As suggested by rtcherry, I used restangular
Configuring the reading of request data:
.config(['RestangularProvider', function(RestangularProvider) {
RestangularProvider.setBaseUrl("/api/v1");
RestangularProvider.setResponseExtractor(function(response, operation, what, url) {
var newResponse;
if (operation === "getList") {
newResponse = response.objects;
newResponse.metadata = response.meta;
} else {
newResponse = response.data;
}
return newResponse;
});
}])
Loading the reminders:
function RemindersCtrl ($scope, $rootScope, Reminder) {
$scope.reminders = Reminder.getList();
}
Adding my custom method to Reminder (not as clean as ngResource, but doable):
.factory('Reminder', ['Restangular', '$filter', function(Restangular, $filter){
var Reminder = Restangular.all('reminder');
var remainingDays = function () {
//do stuff
};
// adding custom behavior
Restangular.addElementTransformer('reminder', false, function (reminder) {
reminder.remainingDays = remainingDays;
return reminder;
});
return Reminder;
}])
Solution by #moderndegree:
I used pure ngResource:
var tastypieDataTransformer = function ($http) {
return $http.defaults.transformResponse.concat([
function (data, headersGetter) {
var result = data.objects;
result.meta = data.meta;
return result;
}
])
};
...
.factory('Reminder', ['$resource', '$http', function($resource, $http){
var Reminder = $resource('/api/v1/reminder/:id', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: tastypieDataTransformer($http)
}
});
Reminder.prototype.remainingDays = function () {
// doing stuff
};
return Reminder;
}])
My controller:
Transaction.query(filter).$then(function (result) {
$scope.days = [];
var transactions = result.resource;
resource[0].remainingDays(); // it works
});
If you wanted to avoid using an additional library, you should be able to do the following:
$resource('/api/v1/reminder/', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: $http.defaults.transformResponse.concat([
function (data, headersGetter) {
return data.objects;
}
])
}
});
This will append your transform to $HttpProvider's default transformer.
Note: Correct me if I'm wrong on this one but I believe this feature requires v1.1.2 or greater.
You may want to try something like restangular.
There is some configuration needed to make that work. An example is here.
I ended up doing the following in order to preserve the meta object directly on the results returned by Reminder.query() (expanding on the answer from #moderndegree).
var Reminder = $resource('/api/v1/reminder/', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: $http.defaults.transformResponse.concat([
function (data, headersGetter) {
return data.objects;
}
]),
interceptor: {
response: function(response) {
response.resource.meta = response.data.meta;
}
}
}
});
That allows you to get the meta value directly on the returned object:
var reminders = Reminder.query(...);
console.log(reminders.meta); // Returns `meta` as expected.
I think it would also be possible to do something similar inside the callback from Reminder.query since the response object is available there as well.