There are many code examples using $resource out there. I came across this one, and the code is quite clearly laid out: https://github.com/apotry/stockwatch
I like this example because:
To call the functions defined is quite simple as shown in the controller code below, but is it a good idea to embed the save in the factory?
My question is: now that Angular 1.2+ includes promises, is this type of code still valid and considered a good practice? How would this code respond to an error state?
Here the resources are defined
app.factory('Stock', ['$resource', function($resource) {
function Stock() {
this.service = $resource('/api/stocks/:stockId', {stockId: '@id'}, {'update': { method: 'PUT' }});
};
Stock.prototype.all = function() {
return this.service.query();
};
Stock.prototype.delete = function(stId) {
return this.service.remove({stockId: stId});
};
Stock.prototype.create = function(attr) {
return this.service.save(attr);
};
Stock.prototype.update = function(attr) {
return this.service.update(attr);
};
Stock.prototype.ohlc = function(stId) {
return $resource('/api/stocks/:stockId/ohlc', {stockId: '@id'}).get({stockId: stId});
}
return new Stock;
}]);
Here is an example of the delete, create and a custom route (ohlc):
$scope.requestOHLC = function (stockid) {
return Stock.ohlc(stockid);
}
$scope.createStock = function() {
$scope.fetchYahooFinanceData($filter('uppercase') ($scope.newCompany["symbol"])).then(function(result) {
$scope.error = false;
$scope.stocks.push(Stock.create(result));
$scope.newCompany = '';
}, function(error) {
$scope.error = true;
});
};
$scope.deleteStock = function(id, idx) {
Stock.delete(id);
$scope.stocks.splice(idx, 1);
};
EDIT
I am trying to work out a simple and clear practice for using $resource based rest routes in angular.
Different from the above code, but based on it. Assume the code below uses a service which is basically the same as the factory above. In this example I call one REST resource to create a new resource (rails table entry), and then pass the newly created id to another call. Note that createPanelHeader references the $scope.selector.paneldata.primer3_parameter_id scope variable. Not sure if this is a good practice either.
I found this would not work unless I uses $promise.then but this seemed a bit convoluted. Am I on the right track?
// Section: Create Panel header
createPrimer3Parameter = function() {
primer3_parameter = Primer3Parameter.create().$promise.then(function(primer3_parameter){
$scope.selector.paneldata.primer3_parameter_id = primer3_parameter.id;
createPanelHeader();
}, function() {
alert('Error creating primer3parameter');
})
};
COMMENT
I am really just trying to work out a simple method for accessing REST resources from a Rails API, with at most 1 level of nesting. I think I am missing something as it seems remarkably difficult.
What I am hearing so far is not to use $resource, even under 1.2. That I should instead use raw $http or Restangular.
Also, there seem to be some 1.2 changes that affect Restangular. The solution feels a bit like a hack to me:
https://github.com/mgonto/restangular#using-values-directly-in-templates
UPDATE
I didn't really come away 100% clear, so I have posted a Bounty: https://bountify.co/write-an-angular-service-for-these-rails-routes-using-restangular
is this type of code still valid and considered a good practice?
This code is valid, but considered deprecated as of 1.2.0-rc3. It will work in all version of angular 1.2 and 1.3 up to but not including 1.3.0-beta10, where automatic promise unwrapping has been removed.
$scope.stocks.push(Stock.create(result));
In the line above you've created an array of promise objects on $scope
. Then in index.html.erb you are referencing the promise directly via the stock
iterator:
<li ng-repeat="stock in stocks">
<div id='symbol'>
{{stock.symbol}}
</div>
The non-deprecated way of handling promises does not allow you to bind directly to the promise like this.
How would this code respond to an error state?
The app is handling errors here:
}, function(error) {
$scope.error = true;
});
and here:
<div ng-show="error">
There was a problem with the Yahoo Finance API. Please try again later.
</div>
For error handling, you're not binding with a promise directly so this works fine in all versions of angular.
First, shelf the javascript directory structure in the stockwatch example. Then, follow this directory structure instead. Finally, integrate Restangular into your project. Create a stockModel
factory that internally instantiates a Restangular
object, but returns the object that will be populated later after the promise resolves (model
). Instead of binding a promise in your partial, bind the unpopulated result object.
.factory('stocksModel', function (Restangular) {
var model = {};
var rest_stocks = Restangular.all('stocks');
model.doSomethingRESTful = function (...) {
// return a promise in case the controller needs it
return rest_carts.some_restangular_method(...)
.then(function() {
model.some_data_which_was_acquired_RESTfully = ...;
});
};
return model;
});
In your controller:
$scope.stocks = stocksModel;
In your partial:
{{stocks.some_data_which_was_acquired_RESTfully}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With