Lets say I have a factory called 'Stuff'.
app.factory('Stuff', function($resource) {
return $resource('api/v1/stuff/', {}, {
getThings: {
method: 'GET',
params: {id: '#id'},
url: 'api/v1/things/:id',
isArray: true
}
});
});
In this factory I have a custom getThings function.
In my controller, if I do this:
$scope.stuffs = Stuff.query();
$scope.things = Stuff.getThings({id: $scope.stuffs[0].id});
It works, and $scope.things is what I want.
But if I do this:
$scope.stuffs = Stuff.query();
$scope.things = $scope.stuffs[0].$getThings();
I get an error in angular-resource.
The ajax call happens to the correct url and I get correct data back but getThings errors out immediatly after getting data, and the only thing left in $scope.things is what looks like a promise:
Object {then: function, catch: function, finally: function}
The error in JS console is:
TypeError: undefined is not a function
at http://dev.blah.com/assets/angular-resource/angular-resource.js?body=1:558:27
at forEach (http://dev.blah.com/assets/angular/angular.js?body=1:326:18)
at $http.then.value.$resolved (http://dev.blah.com/assets/angular-resource/angular-resource.js?body=1:556:17)
at wrappedCallback (http://dev.blah.com/assets/angular/angular.js?body=1:11574:81)
at wrappedCallback (http://dev.blah.com/assets/angular/angular.js?body=1:11574:81)
at http://dev.blah.com/assets/angular/angular.js?body=1:11660:26
at Scope.$eval (http://dev.blah.com/assets/angular/angular.js?body=1:12703:28)
at Scope.$digest (http://dev.blah.com/assets/angular/angular.js?body=1:12515:31)
at Scope.$apply (http://dev.blah.com/assets/angular/angular.js?body=1:12807:24)
at done (http://dev.blah.com/assets/angular/angular.js?body=1:8380:45)
I can't figure out why this isn't working.
I believe a promise is returned on a resource query. Try this:
Stuff.query(function(response) {
response[0].$getThings(function(things) {
$scope.things = things;
);
});
Or:
Stuff.query()
.$promise
.then(function(stuff) {
$scope.stuffs = stuff;
return stuff[0].$getThings();
})
.then(function(things) {
$scope.things = things;
});
See this plnkr http://plnkr.co/edit/qlMrZ9?p=preview. You are returned a $promise on $resource.query() and using the returned value before it is resolved will get you errors.
This is in services.js
var myServices = angular.module('myApp.services', ['ngResource']);
myServices.factory('Stuff', ['$resource', function($resource) {
return $resource('stuff.json', {}, {
getThings: {
method: 'GET',
params: {id: '#id'},
url: ':id/things.json',
isArray: false
}
});
}]);
This is in controllers.js
angular.module('myApp.controllers', [])
.controller('MyCtrl1', ['$scope', 'Stuff', function($scope, Stuff) {
$scope.data = {};
$scope.thingies = [];
$scope.data = Stuff.get();
console.log('is stuffs resolved='+$scope.data.$resolved);
$scope.thingies = Stuff.getThings({id: 'id1'});
console.log('is thingies resolved='+$scope.thingies.$resolved);
}])
.controller('MyCtrl2', ['$scope', 'Stuff', function($scope, Stuff) {
$scope.data = {};
$scope.thingies = [];
$scope.status = [];
Stuff.get(function(response){}).$promise.then(
function(value1) {
$scope.data = value1;
console.log("MyCtrl 2 stuffs="+$scope.data.stuffs[0].id);
Stuff.getThings({id:$scope.data.stuffs[0].id}).
$promise.then(
function(value2){
$scope.thingies = value2;
console.log("MyCtrl 2 thingies="+value2.things);
}, function(error2){
console.log('error in Stuff.getThingies='+error2);
$scope.status = error2;
});
}, function(error1){
console.log('error in Stuff.get='+error1);
$scope.status = error1;
}
);
}]);
I don't understand your line of code. There is something missing for this line to work.
$scope.stuffs[0].$getThings();
You need to show us your actual code or create a plnkr so that we can help you better.
Related
I'm trying get data from db to UI. Url given via provider is getting the data.
Controller in controller DetailsProvider.getDashboardDetails() is getting null.
var appmod = angular.module('project.DetailDashboardController', []);
appmod.controller("DetailDashboardController", ['$rootScope', '$scope', '$state', 'DetailsProvider',function($rootScope, $scope, $state,DetailsProvider) {
console.log("DetailDashboardController --- ");
$scope.DetList= DetailsProvider.getDashboardDetails()
}]);
})(window, window.angular);
provider which will call the list
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
Thanks in advance for any kind of reply!
You should return promise from your service method and do thenable in your controller.
Root Cause : your are returning the newData which will initalized later after completing the ajax call.Before completing it,you are returning the same variable which will be always null.
In provider,
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
and in controller,
$scope.list = function() {
DetailsService.getDashboardDetails(function(data){
varr holdIt = data.data.DList;
});
};
I have this simple app witha factory and a controller:
angular.module('AppName', ['ngResource'])
.factory('apiData', ['$resource', function ($resource) {
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance");
return {
full: function(address){
return apiRequest.get({address: address}).$promise
.then(
function(data){ console.log(data); return data;},
function(){ return 'error'; }
);
}
}
}])
.controller('TwoController', function($scope, apiData){
$scope.price = apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){console.log(data); return data;});
});
The then sections in both factory and controller not returning data from the api resource. Instead it returns e { $promise=Promise, $resolved=true, toJSON=function(), more...} as can be seen in the console.
The url from the example api resource:
https://live.reddcoin.com/api/addr/RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq/balance
And the example on jsfiddle
I'm not sure why $resource doesn't include data(not in object format) inside object return by promise, It display result like below
e {$promise: Promise, $resolved: true} // 1003021043401956 isn't included there
I think get request is expecting object returned from the server. So if it doesn't return an object, then it will not include the same in response
There are 2 ways to solve this problem.
Do return data in object format like {'data': '1003021043401956'}
Create your own get request object inside resource, that will modify before it returns promise object.
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance", {}, {
get: {
method: 'GET',
transformResponse: function(response){
return {data: response}; //creating object
}
}
});
Fiddle
Try this:
.controller('TwoController', function($scope, apiData){
apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){
console.log(data);
$scope.price = data;
});
});
Remember that promises are chained. So eventhough you return data in the success callback, the result of then is still a promise (with data as the inner result).
Working code snippet:
angular.module('AppName', ['ngResource'])
.factory('apiData', ['$resource', function ($resource) {
var apiRequest = $resource("https://live.reddcoin.com/api/addr/:address/balance");
return {
full: function(address){
return apiRequest.get({address: address}).$promise
.then(
function(data){ console.log(data); return data;},
function(){ return 'error'; }
);
}
}
}])
.controller('TwoController', function($scope, apiData){
apiData.full('RszZrK51ur5G67y3Wy6niTnawdYYdBRZEq').then(function(data){console.log(data); $scope.price = data;});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://code.angularjs.org/1.2.23/angular-resource.min.js"></script>
<div ng-app="AppName" ng-controller="TwoController">{{price}}</div>
I am using the following pattern for my REST API, but vm.listing in my controller is always undefined? Probably my pattern is not right? Is there a different pattern to use here? I don't want to call the .get(..) in my controller code.
.factory("listingsResource", ["$resource", "$q", 'appSettings',
function ($resource, $q, appSettings) {
return $resource(appSettings.serverPath + "api/Listings/:id")
}]);
.factory("editService",
var _listing;
var _getListing = function (listingId) {
_listing = listingsResource.get({
id: listingId
});
}
return {
listing: _listing,
getListing: _getListing
};
Controller Code:
createService.getListing(listingId);
vm.listing = createService.listing;
The problem is that when you call listingsResource.get() it returns a promise. Not the data response.
You have to pass the get() a success callback and then set the listing variable inside this callback. I would do something like this:
.service("listingsService", ["$resource", "$q", 'appSettings',
function ($resource, $q, appSettings) {
var _this = this;
_this.listing = {};
var listingResource = $resource(appSettings.serverPath + "api/Listings/:id");
this.getListing = function(listingId){
listingResource.get({id: listingId},
function (data) {
// Success callback
// Set listing keys-value pairs
// do not do: _this.listing = data
_this.listing.id = data.id;
_this.listing.title = data.title;
},
function(err) {
// error callback
console.log(err);
}
)
}
}
])
This works fine with a factory aswell if you prefer. Then in the controller:
listingService.getListing(listingId);
vm.listing = listingService.listing;
I am trying to set a service and want the controllers in my app get the data from the service.
I have something like
angular.module('myApp').service('testService', ['Product',
function(Product) {
var products
//Product is a $resource object to send an http request
Product$.query({
id: 123
}, function(object) {
setProducts(object);
});
var setProducts = function(object) {
products = object;
}
var getProducts = function() {
return products;
}
return {
setProducts: setProducts,
getProducts: getProducts
};
}
]);
in my another controller
angular.module('myApp').controller('productController', ['$scope', 'testService',
function($scope, testService) {
//return undefined...
console.log(testService.getProducts())
}
]);
//testService.getProducts() returns undefined.
I think the reason is because I am making $http request and it's asynchronous so the testService has no idea what the product is when the app first loads. How do I fix this issue? Thanks so much!
I use a promise "q$" to deal with asynch calls:
angular.module('myApp').service('testService', ['Product',
function(Product, $q) {
var products
var setProducts = function(object) {
products = object;
}
var getProducts = function() {
var deferred = $q.defer();
//Product is a $resource object to send an http request
Product$.query({
id: 123
}, function(object) {
setProducts(object);
deferred.resolve(object);
});
return deferred.promise;
}
return {
setProducts: setProducts,
getProducts: getProducts
};
}
]);
angular.module('myApp').controller('productController', ['$scope', 'testService',
function($scope, testService) {
//use a promise
testService.getProducts().then(function(data){
console.log(data);
},
function (error) {
console.log(error);
})
}
]);
The promise has two call backs one for complete and one for error. You can deal with the errors in your view model as needed.
I'm doing some small exercises to learn AngularJS, trying to understand how to work with promises at the moment.
In the following exercise, I'm trying to get some data async. I can see the data in the console.log but the promise is returned NULL.
GET /entries 200 OK
Promise is resolved: null
Anyone experienced can give me some advice to understand what I'm doing wrong ? Thanks for looking!
angular.module('questions', [])
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MainCtrl',
resolve: {
'MyServiceData': function(EntriesService) {
return EntriesService.promise;
}
}
})
})
.service('EntriesService', function($http) {
var entries = null;
var promise = $http.get('entries').success(function (data) {
entries = data;
});
return {
promise: promise,
all: function() {
return entries;
}
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
console.log('Promise is resolved: ' + EntriesService.all());
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all() || [];
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
/****** Thanks everyone for your help so far *****/
After taking the advice of #bibs I came up with the following solution, that's clear using ngResource:
angular.module('questions', ['ngResource'])
.factory('EntriesService', function($resource){
return $resource('/entries', {});
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = [];
EntriesService.query(function(response){
$scope.entries = response;
});
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
You should access the data in the callback. Since entries maybe empty before the data arrives, the all() function is not quite useful in this case.
Try this, you should be able to chain then() method to synchronously get data.
.service('EntriesService', function ($http) {
var services = {
all: function () {
var promise = $http.get('entries').success(function (data) {
entries = data;
}).error(function (response, status, headers, config) {
//error
});
return promise;
},
someOtherServices: function(){
var promise = ....
return promise;
}
return services;
}
});
$scope.entries = [];
EntriesService.all().then(function(data){
$scope.entries = data;
});
If you want the data returned by the server to be immediately reflected in your view:
.service('EntriesService', function($http) {
var entries = [];
var promise = $http.get('entries').success(function (data) {
for (var i = 0; i < data.length; i++) {
entries[i] = data[i];
}
});
return {
promise: promise,
all: entries
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all;
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
You may want to check out $resource to do this for you: http://docs.angularjs.org/api/ngResource.$resource