I have a factory returning an object calling an internal resource containing JSON as so:
.factory('cardFactory', function ($q, $http) {
return {
getOtherStuff: function () {
var deferred = $q.defer(),
httpPromise = $http.get('/static/cards.json');
httpPromise.then(function (response) {
deferred.resolve(response);
}, function (error) {
console.error(error);
});
return deferred.promise;
}
};
});
In my controller I call it like this:
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data.data;
};
cardFactory.getOtherStuff()
.then(cardSuccess, cardError);
In the browser $scope.cards in populated but on the device it doesn't populate.
Any ideas why?
Hmm.., not sure.
I have it in a different way in my Ionic app, working great.
.factory('cardFactory', function ( $http ) {
var promise;
var cards = {
getOtherStuff: function() {
if ( !promise ) {
// $http returns a promise, which has a then function, which also returns a promise
promise = $http.get( '/static/cards.json' ).then(function (response) {
// The then function here is an opportunity to modify the response
// The return value gets picked up by the then in the controller.
return response.data;
});
}
return promise; // Return the promise to the controller
}
};
return cards;
})
Then, on the controller, calling it by:
$scope.getData = function() {
// Call the async method and then do stuff with what is returned inside our own then function
cardFactory.getOtherStuff().then(function(d) {
$scope.cards= d;
});
}
$scope.getData();
Hope it helps.
[EDIT:] Could it be the $http.get url, being relative? Have you tried with an absolute url?
Replace $scope.cards=data.data with "$scope.cards=data"
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data;
};
try removing the leading slash in your url for $http. Try using 'static/cards.json' instead of '/static/cards.json'
I actually had the same problem and this fixed it for me. Hope it helps!
Related
To resolve my issue I have gone through many articles on different sites, but none resolved it.
I'm writing a simple AngularJS application. I'm quite new to Angular. I have written a factory method which call the $http service which gets the data from the web api. Web api is running fine and its returning the JSON object as expected.
Angular Code
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data=WebFactory.getData();
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
$http({
method: "GET",
url: "http://localhost:37103/api/employee",
}).then(function success(response) {
return response.data;
})
.then(function error(response) {
return response;
});
return 'No data';
}
return obj;
});
HTML code
<body ng-controller="controller">
data: {{data}}
<br/>
error: {{error}}
<br />
I have spent 2 days, but still dont know why its not working.
Try something like this instead:
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data = {}
WebFactory.getData().then(function success(response) {
$scope.data = response.data;
});
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
return $http({
method: "GET",
url: "http://localhost:37103/api/employee",
})
}
return obj;
});
First of all, you're missing an ng-app declaration
Secondly, you are misusing the then callback. It accepts three parameters: success callback, error callback, finally callback.
As the first then executes the success, then it executes the second callback that always returns the response, but I assume it is not intended to be that way and you could use the get function which is more easy to use.
It should be:
$http.get("http://localhost:37103/api/employee").then(function(response){
//Do something with successfull response
},
function(error){ //do something with the error});
See documentation about promises
Lastly, you are dealing with promises and async code, yet returning response or string instead of the promise with the result. So the getData() should look like this:
obj.getData = function(){
return $http.get("http://localhost:37103/api/employee");
}
And use the then(success,error,finally) callbacks in the controller or if you want to provide values on the error/finally callbacks in the service, you should use the $q service
obj.getData(){
var deferred = $q.defer();
$http.get(...).then(function(response){
deferred.resolve(response.data);
},
function(error){
deferred.reject("No Data");
});
return deferred.promise;
}
Of course you would have to provide $q service to the WebFactory
I have a simple code here that works however I wanted to display the success and error callbacks. This is my code:
angular
.module('studentInfoApp')
.factory('Student', Student)
.controller('StudentsController', StudentsController)
.config(config);
function config($routeProvider) {
$routeProvider
.when('/', {
controller: 'StudentsController',
templateUrl: 'app/views/student-list.html'
})
}
function Student($resource) {
return $resource('/students');
}
function StudentsController(Student, $scope, $http) {
Student.query(function(data) {
$scope.students = data;
});
}
As you can see the function Student() just returns the resource but I can't get the success and error callback if I use the .then for example. Am I missing something here? Thank you!
Here is a solution:
Student.query(function(data, headers) {
// OK
$scope.students = data;
}, function(response) {
// KO
});
Another one using the promise directly:
Student.query().$promise.then(function(response) {
// OK
$scope.students = response.data;
}, function(response) {
// KO
});
When using angular $resources you can just save the query directly to your variable. It will then hold the promise and when data returns the data itself.
If you need to handle success/error you can just use the saved promise and add success and error callbacks like below.
$scope.students = Student.query();
$scope.students.$promise.then( function(response) {
console.log('success');
}, function (error) {
console.log('error');
});
Managed to get it working, but if there are better ways to do it please feel free to post it also. This is my code now:
function StudentsController(Student, $scope) {
Student.query(function(data) {
$scope.students = data;
})
.$promise.then(function successCallback(response) {
console.log('success');
}, function errorCallback(error) {
console.log('error');
});
}
I'm trying to pass data to $scope.post by doing it this way, but it doesn't want to work like I imagine it to do. I get no errors in the console and the code is inside the PostController.
var PostController = function ($scope, $location, $routeParams, $http, Post, User) {
$scope.post = {};
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
});
}
$scope.getById($routeParams.id);
console.log($scope.post);
}
Here's the routing too:
when('/post/:id', { controller: PostController, templateUrl: 'post.html' }).
Edit, whole PostController added.
getById is an async call, it's not failing, you're just not waiting! Use .then to return a promise and do the assignment in the callback:
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).then(function (result) {
return result.data
});
}
$scope.getById($routeParams.id).then(function(data) {
$scope.post = data;
});
console.log($scope.post); is called before callback, so there is no values.if you want to get the value in console, try this..
$scope.getById = function (id) {
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
console.log($scope.post);
});
}
$http get returns promise.
That means, that function inside success, isn't invoked at once.
It's not intuitive, but that is how promises work.
To track resulting data, insert console.log inside success function
return $http.get('/api/Post/' + id).success(function (data) {
$scope.post = data;
console.log('$scope post: ',$scope.post);
});
You will see data returned from get call to debug ( you can also print this variable in your view ).
How it works:
$http.get returns a promise, and also adds addtional success and error function.
After $http.get, you chain promise to success function
$http.get('/api/Post/' + id).success
which is called after successful server response ( http codes from 200 to 299 ), and error function is called where there is failure ( 400 - 499 codes ).
The first two answers are probably the solution to your problem... since your console.log is executing before the callback to the HTTP request. However, it is good practice to also handle HTTP errors, which could always be a problem. Here is an example of how you would do that:
$http.get('/api/Post/' + id).
success(function(data, status, headers, config) {
//handle success
}).
error(function(data, status, headers, config) {
//handle error
});
Dear AngularJS savies,
How to set $scope.data in the controller having a promise returned from a factory. All I can do is work with the data returned in the scope of the method of the factory's object and I cannot "load" the data in a value existing in the controller's scope. How can I pass the data into controller's scope?
The code sequences as following
This is the factory:
var features = {};
// the method returns a promise tot he controller needed to be delt with .then()
features.getPromise = function(){
//make a promise
var promise = $http({method: 'GET', url: '../../LIBS/inc/getAllGeoFeatures.php'})
.success(function(data, status, headers, config){
return data;
})
.error(function(data, status, headers, config){
$log.warn(data, status, headers, config);
});
return promise;
};
This is the controller:
$scope.data = 'null';
factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
// here I can work with the data but I cannot share it with the controller
// i.e. with the view
});
$log.info($scope.data); //$scope.data is still null and I need it loaded with the data
I need some counceling because I sense I go nowhere
I even tried to load $scope.data with the outcome of the method, but I only get the promsise object and not the data:
Object {then: function, catch: function, finally: function}
Please advise.
P.S. I use angular 1.2.x
Thank you very much for your time and patience.
It should be
factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
}).then(function(){
// here you can see $scope.data updated with a new value
$log.info($scope.data);
});
as alternative:
var promise = factGetFeat.getPromise().then(function(promise){
$scope.data = promise;
$log.info($scope.data); //gets the object all right
});
promise.then(function(){
// here you can see $scope.data updated with a new value
$log.info($scope.data);
});
.then is evaluated when 1st promise resolved
You are doing it almost right. You only need to return the promise from your service.
If I understand you question you are concerned about $scope.data being null when you call $log.info($scope.data) on the very last page. And that is perfectly correct. $scope.data will be set later, when the HTTP call is finished successfully.
If you need to do any operations only when the data arrived, you must include it success callback.
Here is how it could look like:
var app = angular.module('app',[]);
app.factory('featuresService', ['$http', '$log', function($http, $log) {
var getPromise = function() {
//create the promise, this will be returned from this function
var promise = $http({method: 'GET', url: '../../LIBS/inc/getAllGeoFeatures.php'});
//on error do some logging here
promise.error(function(data, status, headers, config) {
$log.warn(data, status, headers, config);
});
return promise;
};
return {
getPromise: getPromise;
}
}]);
app.controller('testCtrl', 'featuresService', function($scope, featuresService) {
//set initial values
$scope.data = null;
$scope.vectorAllLibs = null;
var init = function() {
featuresService.getPromise().then(function(data) {
$scope.data = data;
$scope.vectorAllLibs = convertVectorAllLibs(data);
};
};
var convertVectorAllLibs = function(data) {
return ol.source.GeoJSON({ projection: 'EPSG:3857', object: data });
};
$scope.processVectorAllLibs = function() {
if (!$scope.vectorAllLibs) {
alert('sorry, no data yet!');
return;
}
//process here
};
init();
});
I'm implementing just a thin wrapper around $http for our REST API, and I'm wanting it to return a promise in the same way as $http does (after I massage the data).
Here's my service:
Services.service('Item', ['$http', '$q', function($http, $q){
var deferred = $q.defer();
var getSuccess = function(data, status, headers, config){
var item = angular.copy(data);
item.primaryImage = 'https://my.cdn.com/' + item.meta.images[0].s3id;
if(item.meta.source_link !== null) {
item.sourceLink = item.meta.source_link.url;
}
deferred.resolve(item, data, status, headers, config);
};
var getError = function(data, status, headers, config) {
deferred.reject(data, status, headers, config);
};
this.get = function(userID, itemID) {
$http({
method: 'GET',
url: '/api/items/' + userID + '/' + itemID
}).success(getSuccess).error(getError);
return deferred.promise;
};
}]);
But from my understanding of the documentation, I have to use .then(success, error, always) rather than .success().error().always() like I can with $http.
Is it possible to implement promises in the same way that $http does? I would love to do this
var req = Item.get($routeParams.userID, $routeParams.itemID);
req.success(function(item){
window.console.log('Got an item!', item);
});
.error(function(item){
window.console.log('Damn. It failed.')
})
This question made me search for a bit after understanding what you actually wanted.
I made a plnkr showing how I solved this: http://plnkr.co/edit/LoCuwk26MEZXsugL1Ki5
Now, the important part is:
var promise = defered.promise;
promise.success = function(fn) {
promise.then(function(res) {
fn(res);
});
return promise;
};
promise.error = function(fn) {
promise.then(null, function(err) {
fn(err);
});
return promise;
};
return promise
This code comes straight from the angular source code. So I believe it is the way to go if you want to replicate that style.
I did notice an error in your code though. All services are singletons. Which means you only create one deferred object. You should create one on each call and use that.