AngularJS Services (Update/Save) - javascript

New to AngularJS and trying to get a grasp of the framework, and trying to build a basic CRUD app. I can't seem to figure out what is needed to Update an existing record. Here is my service:
angular.module('appServices', ['ngResource']).
factory('App', function ($resource) {
var Item = $resource('App/:AppId', {
//Default parameters
AppId: '#id'
}, {
//Actions
query: {
method: 'GET',
isArray: true
},
getById: {
method: 'PUT'
},
update: {
method: 'POST'
}
});
return Item;
});
I can run a basic Get all query, and getById to populate an edit form, but that's where I'm stuck. Here is example code for getById
$scope.apps = App.query();
$scope.getEdit = function(AppId) {
App.getById({id:AppId}, function(app) {
$scope.original = app;
$scope.app = new App(app);
});
};
$scope.save = function() {
//What type of information should go here?
//Do I need to make changes to the appServices?
};
I guess, I'm just not sure what's next concerning Updating existing information, or how the "app" object gets passed to the API, can anyone point me in the right direction, or show me a quick update method?

This is a really messy way of handling save operations in angular. For one - you should not be using PUT operations for retrieval requests and secondly - all of this is already built-in to angular. See below.
var Item = $resource( 'App/Details/:AppId', { AppId: '#id' } );
var item = Item.get({ id: 1 }, function( data ) {
data.setAnothervalue = 'fake value';
data.$save();
);
What I'm doing here is retrieving an "Item" and then immediately saving it with new data once it's returned.
Angular JS provides a stack of defaults already, including query, save, remove/delete, get.etc. And for most RESTful APIs, you really shouldn't need to add much, if anything at all. See the resource docs for more information, particularly the information on defaults: http://docs.angularjs.org/api/ngResource.$resource
Additionally, once you get a handle on that - you may want to use $save for both create/update operations, but using POST/PUT (RESTful conventions). If you do, see my article that I wrote about not too long ago: http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/

After doing a bit more research, and reviewing Daniel's link (thanks). I got it working.
Controller method:
$scope.save = function() {
$scope.app.update();
};
Service Factory:
var Item = $resource('App/Details/:AppId', {
//Default parameters
AppId: '#id'
}, {
//Actions
query: {
method: 'GET',
isArray: true
},
getById: {
method: 'PUT'
},
update: {
method: 'POST'
}
});
Item.prototype.update = function (cb) {
console.log(this.AppId);
return Item.update({ AppId: this.AppId },
angular.extend({}, this, { AppId: undefined }), cb);
};
return Item;

Related

angular $resource not working as expected

I have a very simple address application in AngularJS. It connects to an API using $resource.
The ID I use is the mobilephone number of the person (I know it's not the best way to do it, but it's just an sample application to show a 3-tier application setup) So I've 2 pages with the same form:
The problem i'm facing is that it uses the same $resource for saving a new address and saving an edited address. When iḿ saving a new address it has to use the url http://127.0.0.1:5000/api/contacts/ without an id appended on it (the new ID it will get on the api/database side is the filled in mobile phone number)
When I edit an existing address and click the save button it has to use another url; http://127.0.0.1:5000/api/contacts/#mobilePhone.
So i've read the angular documentation on https://docs.angularjs.org/api/ngResource/service/$resource which states that you can override your paramDefaults in your actions. So that is what I try to do using this code:
$resource('http://127.0.0.1:5000/api/contacts/:id',{id:'#mobilePhone'},{
get: {
method: 'GET'
}, update: {
method: 'PUT'
}, save: {
method: 'POST',
id:''
}
},{});
which seems to be correct given the information. It appends the mobilePhone number on every GET and every PUT the get and update method respectively. When it calls the save method it should override the :id with an empty string, but it doesn't do that.
Clearly i'm doing something wrong.
If you need more code snipets let me know, I tried to keep it as clean as possible.
Update:
This is how I call the save method:
....
.controller('MovieCreateController',function($scope,$state,$stateParams,Movie){
$scope.movie=new Movie();
$scope.addMovie=function(){
$scope.movie.$save(function(){
$state.go('movies');
});
}
}
And this is the edit method:
....
.controller('MovieEditController',function($scope,$state,$stateParams,Movie){
$scope.updateMovie=function(){
$scope.movie.$update(function(){
$state.go('movies');
});
};
$scope.loadMovie=function(){
$scope.movie=Movie.get({id:$stateParams.id});
};
$scope.loadMovie();
});
There is not much code in your question, so I'll try to explain what you should do to use $resource.
Have a look at following code:
// The $resource service is a helper to create a 'constructor' function
// Contact below is a function
var Contact = $resource('http://127.0.0.1:5000/api/contact/:id',{id:'#mobilePhone'}, {
get: {
method: 'GET' // You don't need to override the GET
}, update: {
method: 'PUT'
}, save: {
method: 'POST'
}});
// Be sure to create an 'entity' from the Contact $resource
// The 'new' will create a $resource instance with $update, $save methods overridden methods
var contact = new Contact({name: 'foobar'});
contact.$save(); // Will send a POST request
contact.mobilePhone = 2; // This is your id !
contact.$update(); // Will send a PUT request
If your resources always have a RESTful representation, I suggest that you use, as per suggested at angular discussion on issue#9807:
resource.prototype.$save = function() {
if (this.id) {
return this.$update();
} else {
return this.$create();
}
};
..rather that always overriding your $resource methods.
This is how you need to call your save method
$scope.movie=new Movie();
$scope.addMovie=function(){
$scope.movie.$save(function(){
$state.go('movies');
});
}
This is how you need to call your edit method
$scope.movie=new Movie();
$scope.updateMovie=function(){
$scope.movie.$update({ "mobilePhone": $stateParams.id},function(){
$state.go('movies');
});
};
For that you need to create a factory for $resource.which is always recommendable
Try this
.factory('movie', ['$resource', function ($resource) {
return $resource('http://127.0.0.1:5000/api/contacts/:id',{id:'#mobilePhone'},{}, {
update: { method: 'PUT' },
query: {
method: 'GET',
isArray: false
}
})
}])
Inject your factory in your controller
.controller('MovieCreateController',['$scope','$state','$stateParams','movie',function($scope,$state,$stateParams,Movie){
}]);

Reading data from $resource.get() in AngularJS

JSON/XML from REST
{
litm: "T00000245",
lotn: "00004"
}
<jdeSerials>
<litm>T00000245</litm>
<lotn>00004</lotn>
</jdeSerials>
AngularJS controller
//Searching a product with serial number/LOTN
$scope.searchProduct = function () {
var lotn = $scope.jdeSerials.lotn;
console.log("searchProduct---->" + lotn);//log-->searchProduct---->00004
$scope.JdeSerials = lotnService.get({id: lotn}, function() {
console.log($scope.jdeSerials);//log-->[object Object]
console.log($scope.jdeSerials.litm);//log-->undefined!!!!!
});
//var litm = $scope.jdeSerials.litm;
//$scope.jdeproduct = productService.get({id: litm});
};
AngularJS service
angular.module('lotnService', ['ngResource'])
.factory('lotnService', ['$resource',
function ($resource) {
console.log('------lotmService-----');
return $resource(
'http://localhost:8080/RMAServer/webresources/com.pako.entity.jdeserials/:id',
{},
{
update: { method: 'PUT', params: {id: '#lotn'} }
});
}]);
Question
How can I get a value to $scope.jdeSerials.litm? Is there any better idea to solve this like creating a service which handles this two GETs? I think that reason is the GET method is asynchronous, but what is the best solution to handle situations like this?
EDIT/update
I changed the service call like this:
$scope.JdeSerials = lotnService.get({id:lotn})
.$promise.then(function(jdeSerials) {
$scope.jdeSerials = jdeSerials;
console.log("1--------------->LITM:"+$scope.jdeSerials.litm);
});
I got the LITM, BUT I got the errormessage as well:
TypeError: Cannot read property 'then' of undefined
Try to create a get method in your resource.
angular.module('lotnService', ['ngResource'])
.factory('lotnService', ['$resource', function ($resource) {
return $resource( 'http://localhost:8080/RMAServer/webresources/com.pako.entity.jdeserials/:id',
{},
{
get: { method: 'GET', params: {id: '#lotn'}},
update: { method: 'PUT', params: {id: '#lotn'} }
});
}]);
Then in your controller, call method get from service:
lotnService.get({id:lotn}).$promise.then(
function(jdeSerials) {
$scope.jdeSerials = jdeSerials;
console.log("1--------------->LITM:"+$scope.jdeSerials.litm);
});
What angular js version are you using?
Does the following work ?
lotnService.get({id:lotn}).then(
function(jdeSerials) { ... }
);
(without the $promise)
I was browsing the docs and also angular-resource.js source for previous versions and it appears that the synthax has changed somewhere along the line.
On angular-resource.js 1.2.0 source:
The Resource instances and collection have these additional properties:
$promise: the {#link ng.$q promise} of the
original server interaction that created this * instance or
collection.
On 1.0.8 there is no mention of the $promise propery, however.

displaying Data from multiple tables with AngularJs

I have been reading different posts with similar questions but I cannot get this figured out. I have a Job class that is linked to different tables such as Customer and Employee. The Data is coming back from the Database but I cannot get the Angular Table to display the linked classes. The suggestions have been to use different mods, restangular, angular-activerecord, ModelCore and this method
angular js model relationships
I am not sure the best route to take and what would be the simplest way of doing it.
app.factory('Job', function ($resource) {
return $resource('/api/apiJob/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('jobFactory', function ($http) {
return {
updateJob: function (job) {
return $http.put('/api/apiJob/' + job.JobId, job);
}
};
});
app.factory('Customer', function ($resource) {
return $resource('/api/apiCustomer/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('customerFactory', function ($http) {
return {
updateCustomer: function (customer) {
return $http.put('/api/apiCustomer/' + customer.CustomerId, customer);
}
};
});
'use strict';
app.controller('JobCtrl', function ($scope, Job, $resource, $route, jobFactory, notificationFactory, $http) {
////GET Jobs
$scope.jobArray = Job.query()
//New Job Modal
$scope.NewJobModal = function () {
$('#NewJobModal').modal();
}
$scope.submitJob = function () {
var data = {
JobId: $scope.JobId,
JobNumber: $scope.JobNumber,
JobName: $scope.JobName,
CustomerName: $scope.CustomerName,
JobDescription: $scope.JobDescription,
OriginalContract: $scope.OriginalContract,
BillingDate: $scope.BillingDate,
}
$http.post('/api/apiJob/PostNewJob', data).success(function (data, status, headers) {
console.log(data);
});
window.top.location.reload();
};
//End New Job Post
//Delete Job
$scope.deleteJob = function (job) {
Job.delete({ id: job.JobId }, function () {
if ($scope.jobArray.length === 1) {
$scope.jobArray.splice(-1, 2);
} else {
$scope.jobArray.splice(job.JobId - 1, 2);
}
window.top.location.reload();
});
};
//End Delete Job
$scope.updateJob = function (job) {
jobFactory.updateJob(job).success(successCallback).error(errorCallback);
};
$scope.job = [];
var successCallback = function (data, status, headers, config) {
notificationFactory.success();
return $('#editJobModal').modal('hide');
};
var errorCallback = function (data, status, headers, config) {
notificationFactory.error(data.ExceptionMessage);
};
//End Edit Job
}); //End Job Controller
What It looks like in the Browser Console
0: {$id:1, JobId:1, JobNumber:2534, JobName:St.Lukes, JobDescription:Rebuilding Cafeteria,…}
$id: "1"
BalanceDue: 89654123
BalanceToBill: 541256
BillingDate: "2014-08-12T14:43:22.507"
BillingForm: "Invoice"
Budget: 854523658
CertPayroll: true
ChangeOrders: [{$id:4, ChangeOrderId:1, ChangeOrderNumber:7854, ChangeOrderDate:2014-08-12T14:43:22.673,…}]
ContractDate: "2014-08-12T14:43:22.507"
Customers: [{$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}]
0: {$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}
Employees: [{$id:3, EmployeeId:2, AccountName:Ham Sandwich, EmployeeFirstName:Scott, EmployeeLastName:Willis,…}]
JobAddress: "1234 Mason Rd"
JobCity: "Katy"
JobCost: 784556124
Updated Factory
app.factory('JobGet', function ($http, $q) {
var data = $http({
method: 'GET',
url: '/api/apiJob'
})
return {
query: function () {
var deferred = $q.defer();
setTimeout(function () {
deferred.resolve(data)
}, 2000);
return deferred.promise;
}
};
});
Network Response Tab
[{"$id":"1","JobId":1,"JobNumber":2534,"JobName":"St.Lukes","JobDescription":"Rebuilding Cafeteria","OriginalContract":1250210,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Rudy Sanchez","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814569654,"JobFax":2814563251,"JobHidden":false,"Customers":[{"$id":"2","CustomerId":2,"CustomerName":"Grove at Wilcrest","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"56328 Richmond Ave","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77042,"CustomerWebsite":"grovewilcrest.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":1,"Job":{"$ref":"1"}}],"Employees":[{"$id":"3","EmployeeId":2,"AccountName":"Ham Sandwich","EmployeeFirstName":"Scott","EmployeeLastName":"Willis","EmployeeTitle":"Admin","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"testing#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":1,"Job":{"$ref":"1"}}],"ChangeOrders":[{"$id":"4","ChangeOrderId":1,"ChangeOrderNumber":7854,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":1,"ChangeOrderAttn":"Frank Harvel","ChangeOrderHidden":false,"JobId":1,"Job":{"$ref":"1"}}]},{"$id":"5","JobId":2,"JobNumber":12343,"JobName":"Katy Mills","JobDescription":"New Mall Bathrooms","OriginalContract":32623212,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Mike Hall","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814456965,"JobFax":2814563225,"JobHidden":false,"Customers":[{"$id":"6","CustomerId":1,"CustomerName":"City Center","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"123453 HWY 6","CustomerCity":"Katy","CustomerState":"TX","CustomerZipcode":77493,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":2,"Job":{"$ref":"5"}}],"Employees":[{"$id":"7","EmployeeId":3,"AccountName":"Ice Cream","EmployeeFirstName":"Aaron","EmployeeLastName":"Horstmann","EmployeeTitle":"Office Bitch","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"aaron#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":2,"Job":{"$ref":"5"}}],"ChangeOrders":[{"$id":"8","ChangeOrderId":2,"ChangeOrderNumber":1823,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"Work Orders","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":2,"ChangeOrderAttn":"Rosie Sanchez","ChangeOrderHidden":false,"JobId":2,"Job":{"$ref":"5"}}]},{"$id":"9","JobId":3,"JobNumber":12398,"JobName":"City Center","JobDescription":"Remodeling Yard House","OriginalContract":56325412,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Shawn Saulnier","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814256965,"JobFax":2814565325,"JobHidden":false,"Customers":[{"$id":"10","CustomerId":3,"CustomerName":"Twin Peaks","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"8473 Katy Fwy","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77043,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":3,"Job":{"$ref":"9"}}],"Employees":[{"$id":"11","EmployeeId":1,"AccountName":"Not Sure","EmployeeFirstName":"Frank","EmployeeLastName":"Harvel","EmployeeTitle":"Manager","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"texas45#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":false,"JobId":3,"Job":{"$ref":"9"}}],"ChangeOrders":[{"$id":"12","ChangeOrderId":3,"ChangeOrderNumber":45324,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed again","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":3,"ChangeOrderAttn":"Travis Dillard","ChangeOrderHidden":false,"JobId":3,"Job":{"$ref":"9"}}]}]
First of all, this is a work in progress. Your code is very large and to solve this I removed a lot o noise from your plunkr, I left there only what's essential to make it work and only the code involved in it.
Working Demo
First thing to notice, on your JobController you are doing:
////GET Jobs
$scope.jobArray = Job.query();
This worked on previous versions of angular, on the current version there is no automatic promise unwrapping anymore, so you must use the then function:
////GET Jobs
Job.query().then(function(retrievedData){
$scope.jobArray = retrievedData;
});
Notice that on the plunkr I "mocked" the returning of data using $q and a timeout, I actually cleaned the json leaving only the properties that are used on the table, just to make it simpler, you don't need to do that on your code ok? Just keep that part as it is.
Maybe you'll have to modify it just to resolve the promise with the returned data, but this is up to you, the important thing is to return a promise from your query() method and resolve it.
On the HTML I noticed that you are binding the customer name like this:
<td>{{job.Customers.CustomerName}}</td>
But on your Json, the Customers property is an array of customers, so you either return one customer from your api or bind it like this:
<td>{{job.Customers[0].CustomerName}}</td>
I also noticed that there are a lot of jQuery references on your controllers like this:
$('#editJobModal').modal();
This is not recommended and I don't think it will work at all, when dealing with the DOM, always use directives and comunicate with them using bindings, thats the angular way.
Well after all this, my plunkr is showing the table with the 2 fake customers from the Json. Now I suggest you to study that code and apply those principles to your app.
I hope I could help or at least point you at the right direction.

AngularJS - Check my implementation of resource factory

Just starting out on AngularJS & js (being a backend developer) and this is the first Javascript MVC framework which I have ever worked on so please go easy...
I have a restful json API which I would like to consume using AngularJS.
In order to implement this, I have created two factories, one singular for when a controller needs to query the factory with an id, and a plural factory for when id is not required.
e.g. below:
Controller to list all products:
app.controller('ProductController', function($scope, ProductsFactory) {
$scope.products = [];
init();
function init()
{
$scope.products = ProductsFactory.query();
}
});
Factories:
app.factory('ProductsFactory', function($resource) {
return $resource('/xxx/xxx/xxx/api/v1/product', {}, {
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
});
});
app.factory('ProductFactory', function($resource) {
return $resource('/xxx/xxx/xxx/api/v1/product/:id', {}, {
show: { method: 'GET' },
update: { method: 'PUT', params: { id: '#id' } },
delete: { method: 'DELETE', params: { id: '#id' } }
});
});
Question 1: Am I implementing the resource factory correctly?
Question 2: Is there a way of just using one factory for Products? e.g. allowing the factory to decide that id is not necessary for query and create, but is required for show, update and delete methods?
Yes, you can use just 1 factory :
app.factory('ProductFactory', function($resource) {
return $resource('/xxx/xxx/xxx/api/v1/product/:id', { id : '#id'}, {
update: { method: 'PUT' },
});
});
You don't need to specify the 'params' object to every requests. Defining it for the $resource is often enough (but if you want to overwrite it of course you can use it).
Notice that you don't need to define the CRUD methods since the $resource already implements them (as stated in the doc : http://docs.angularjs.or/api/ngResource.$resource).
At the moment, you just need to define a custom method update if you want to use "PUT" but a pull request is opened (https://github.com/angular/angular.js/pull/3416) and I hope we can expect to see it implemented soon.

How to specify different URLs for collections vs. single records with ngResource

I am trying to use ngResource to consume a firebase rest API. This API uses slightly different URLs for retrieving collections vs individual records. For example, I have a collection that I access with:
https://angular-resource-test.firebaseIO.com/systems.json
But if I want to access an individual system I use:
https://angular-resource-test.firebaseIO.com/systems/1.json
How do I specify a parameter-based URL for this in the resource declaration?
Normally I would do something like
app.factory('System', ['$resource', function($resource) {
var System = $resource(
'https://angular-resource-test.firebaseIO.com/systems/:id.json',
{id: "#id"},
{update: {method: "PUT"}}
);
return System;
}]);
But that fails for the collection because it lacks the trailing .json. Alternatively, when I specify a URL that works for the collection, the case of selecting individual rows fails. See this jsfiddle for an example:
http://jsfiddle.net/D5E6w/15/
There are 2 methods that send an HTTP GET in a resource.
get : Expect to receive an object
query : Expect to receive an array
Your api isn't very restful and because of this, you will need 2 resources to do what you want since they use different URI (see Carl's answer). I dont know if you can edit your REST service, but the good way to do it would be :
https://angular-resource-test.firebaseIO.com/systems/ for a query (expect an array)
https://angular-resource-test.firebaseIO.com/systems/:id for a get. (expect an object)
With this service, you could use your resource :
var System = $resource(
'https://angular-resource-test.firebaseIO.com/systems/:id',
{id: "#id"},
{update: {method: "PUT"}}
);
You would do your calls like this :
var systems = System.query({});
var system = System.get({id:1});
Your problem should be solved by using isArray: true for your query and get methods for System and SystemType. It has to do with how your json is formatted on the server-side. See angular docs for expanded discussion. http://jsfiddle.net/D5E6w/24/
{
update: { method: "PUT" },
query: { method: "GET", isArray: true },
get: { method: "GET", isArray: true }
}
Here is a working example with both a collection of systems and a single record. Note the isArray value for each. http://jsfiddle.net/D5E6w/51/
here is my solution with replacing the entire $resource URL. I needed that because I am using HAL Rest response and when paginating for instance, I wanted to replace the entire URL and not only params in it.
app.factory('$rest', ['$resource', 'HALParser', function($resource, HALParser) {
return function($url) {
$url = ($url == null) ? 'http://localhost:8000/:type' : $url;
return $resource($url, {type: ''}, {
update: { method:'PUT' },
get : {
method: 'GET',
transformResponse: [function(data) {
return (new HALParser()).parse(angular.fromJson(data));
}]
}
});
}
}]);
and then,
app.controller('VendorsController', ['$scope', '$rest',
function($scope, $rest) {
$scope.data = $rest().get({type: 'vendors'});
$scope.create = function() {
$rest().save({type: 'vendors'}, {name: $scope.item});
};
$scope.load = function($item) {
console.log($item);
};
$scope.page = function($url) {
$scope.data = $rest($url).get();
};
}]);
I simply wrapped $resource return from my service info a function with an argument URL.

Categories

Resources