Angular Js:How to pull factory data to the controller - angularjs

Hi I am trying to pull my angular js factory data to my controller,
please have a look if there is any issue.
factory.js
.factory('History', ['$http', '$q', function ($http, $q) {
function history () {
// angular.extend(SearchOptions.getDefaults(), params, options);
var deferred = $q.defer();
$http({
method: 'GET',
url: '/res/orders/' + 31536427 + '/history-group'
})
.success(function (res) {
// console.log(res);
})
.error(function (err) {
// TODO error handler
deferred.reject(err);
});
return deferred.promise;
}
return {
history: history
};
}]);
controller.js
.controller('HistoryCtrl', ['$scope', '$state', '$stateParams', 'History', function($scope, $state, $stateParams, History) {
History.history().then(function(res) {
console.log(res);
$scope.history = res.body;
console.log($scope.history);
}, function(err) {
// TODO error handler
console.log(err);
})
.finally(function(err) {
});
}]);

You need to pass the response in the success function in the 'History' factory as below:
.success(function (res) {
// console.log(res);
deferred.resolve(res);
})

The issue with your code is you are not resolving the promise after getting the data in the success callback function. Resolve it as shown below in the .success callback function :
deferred.resolve(res);
Few points to improve your code:
$http service in Angular by default returns a promise. Hence, you don't have to explicitly construct a promise using $q which is an anti pattern (Deferred anti-pattern). Just returning $http object from the service itself will do the
job. Doing return $http() is equivalent to return deferred.promise() in your code.
.success and .error callbacks are deprecated in the latest version(1.6) of AngularJs (Deprecation Notice). The disadvantage of using these is that they are not chainable as they ignore return values. Hence, it is better to use .then instead.
Applying above changes, your service can be refactored to below :
.factory('History', ['$http', function ($http) {
function history () {
return $http({
method: 'GET',
url: '/res/orders/' + 31536427 + '/history-group'
})
.then(successCallback, errorCallback);
}
function successCalback (res) {
return res;
}
function errorCalback (err) {
return err;
}
return {
history: history
};
}]);

Related

Angular promise resolved before factory execution

We are trying to update a Factory which returns a promise. The original Factory uses $http->success->error and the controller has a .then(...).
We want to "migrate" from success/error to then/catch, but we get the following error message in the controller: TypeError: Cannot read property 'then' of undefined.
The Factory methods are the following ():
'use strict';
xmsbsExtranet.factory('projectsTimeTrackingServices', ['$resource', '$http', '$log', '$q', 'membershipServices',
function ($resource, $http, $log, $q, membershipServices) {
var serviceBase = 'http://localhost:51617/api/';
var _model = {};
var service = {
model: _model,
getByProjectId: _getByProjectId_new,
upsert: _upsert,
};
return service;
function _getByProjectId_old(projectId) {
var deferred = $q.defer();
$http({
method: "Get",
url: "../api/projectsTimeTracking/project/" + projectId
}).success(function (response) {
deferred.resolve(response);
}).error(function (err, status) {
//membershipServices.logOut();
deferred.reject(err);
});
return deferred.promise;
};
function _getByProjectId_new(projectId) {
$http.get("../api/projectsTimeTracking/project/" + projectId)
.then(function (response) {
return response.data;
}).catch(function (err, status) {
//membershipServices.logOut();
return err;
});
};
}]);
The "short" version of the controller is as follows:
projectsTimeTrackingServices
.getByProjectId(vm.project.xrmId)
.then(function (data) {
//do something with the data
});
When the service executes the method "_getByProjectId_old", everything Works as expected. But if I change it to "_getByProjectId_new", I get the afformentioned error.
Any Help will be greatly appreciated.
Best regards
Correct me if I'm wrong - but you're not actually returning anything from the 'new' version of this function.
function _getByProjectId_new(projectId) {
//note that nothing is returned in THIS scope.
$http.get("../api/projectsTimeTracking/project/" + projectId)
.then(function (response) {
return response.data;
}).catch(function (err, status) {
//membershipServices.logOut();
return err;
});
};
You can fix this by using this code:
function _getByProjectId_new(projectId) {
//note the new return statement
return $http.get("../api/projectsTimeTracking/project/" + projectId)
};
or this code (depending on whether you want to return 'response' or 'response.data'):
function _getByProjectId_new(projectId) {
//note the new return statement
return $http.get("../api/projectsTimeTracking/project/" + projectId)
.then(function (response) {
return response.data;
});
};
I'd refrain from catching the error within this function, since if you catch the error, your controller code will not be able to catch it.
You should probably read some documentation on promises and then/catch chaining, it's a little tricky.

MVC and Angularjs : promise does not waiting data

i'm newby in angularjs i researched on the internet but i couldn't find any suitable solution for my problem. I made an http call to get some data from controller. The controller side is okay. But the client-side, promise does not waiting data. Here codes that I wrote ;
//service code
angular.module("myApp").service('$myService', function ($http, $q) {
this.getDataArray = function () {
var deferred = $q.defer();
$http.get('../Home/GetDataArray')
.success(function success(response) {
deferred.resolve(response);
})
.error(function () {
console.log("error getting data array");
deferred.reject();
});
return deferred.promise;
};
}
// controller-code
angular.module("myApp").controller('dataController', function ($scope, $http, $myService) {
$scope.getDataFromService = function () {
$myService.getDataArray().then(function (response) {
$scope.dataArray = response.data;
});
};
});
}
When i call the getDataFromService method at first $scope.dataArray is empty, but the second call, $scope.dataArray is filled with data. Where is the problem? Thanks for helps.
Not an angular expert myself. This is just how I did it when I ran into the same problem. Try this:
Controller:
angular.module("myApp").controller('dataController',[ '$scope', 'Service1', '$http', function ($scope, Service1, $http) {
var deferred = Service1.getDataArray().$promise;
return deferred.then(function successCallback(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
$scope.dataArray = response.data;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
})
}])
and service:
var service = angular.module("myApp").service('myService', ['ngResource']);
myService.factory('Service1', ['$resource',
function ($resource) {
return $resource('../Home/GetDataArray', {}, {
get: { method: 'GET', isArray: true },
});
}])
The idea is that your service isn't the one that should wait for a return, your controller is. So you should wait for the promise in your controller not your service. In my example I am using factories because, well, that's how I got around it in my project, you can try and implement this directly if you don't want to use a factory.

Cannot set property from angularjs service

I am trying to set value in html page from angularjs controller.
I am getting value from web api in service but I have issue that I am always getting error:
TypeError: Cannot set property 'messageFromServer' of undefined
But I can't figure what am I doing wrong here. What am I missing?
On the html part I have:
<div ng-app="myApp" ng-controller="AngularController">
<p>{{messageFromServer}}</p>
</div>
In the controller I have:
var app = angular.module('myApp', []);
app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
$scope.messageFromServer = "When I set it here it works!"
messageService.getMessage();
}]);
app.service('messageService', ['$http', function ($http) {
this.getMessage = function ($scope) {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
}).success(function (data) {
$scope.messageFromServer = data;
console.log(data);
}).error(function (data) {
console.log(data);
})
};
}]);
Basically the problem is, you missed to $scope object to the service getMessage method. But this is not a good approach to go with. As service is singleton object, it shouldn't manipulate scope directly by passing $scope to it. Rather than make it as generic as possible and do return data from there.
Instead return promise/data from a service and then assign data to the scope from the controller .then function.
app.service('messageService', ['$http', function ($http) {
this.getMessage = function () {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
//you could have do some data validation here
//on the basis of that data could be returned to the consumer method
//consumer method will have access only to the data of the request
//other information about request is hidden to consumer method like headers, status, etc.
console.log(response.data);
return response.data;
}, function (error) {
return error;
})
};
}]);
Controller
app.controller('AngularController', ['$scope', 'messageService',
function ($scope, messageService) {
$scope.messageFromServer = "When I set it here it works!"
messageService.getMessage().then(function(data){
$scope.messageFromServer = data;
});
}
]);
Don't use $scope in your service, just return the promise from $http.
var app = angular.module('myApp', []);
app.service('messageService', ['$http', function ($http) {
this.getMessage = function () {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
});
};
}]);
app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
messageService.getMessage().then(function(data) {
$scope.messageFromServer = data;
});
}]);
In this example you can unwrap the promise in your controller, or even better you can use the router to resolve the promise and have it injected into your controller.
app.config(function($routeProvider) {
$routeProvider.when('/',{
controller: 'AngularController',
templateUrl: 'views/view.html',
resolve: {
message: function(messageService) {
return messageService.getMessage();
}
}
});
});
Then in your AngularController, you'll have an unwrapped promise:
app.controller('AngularController', ['$scope', 'message', function ($scope, message) {
$scope.messageFromServer = message;
}]);

AngularJS : returning data from service to controller

I am trying to create a service to get json and pass it to me homeCtrl I can get the data but when a pass it to my homeCtrl it always returns undefined. Im stuck.
My Service:
var myService = angular.module("xo").factory("myService", ['$http', function($http){
return{
getResponders: (function(response){
$http.get('myUrl').then(function(response){
console.log("coming from servicejs", response.data);
});
})()
};
return myService;
}
]);
My Home Controller:
var homeCtrl = angular.module("xo").controller("homeCtrl", ["$rootScope", "$scope", "$http", "myService",
function ($rootScope, $scope, $http, myService) {
$scope.goData = function(){
$scope.gotData = myService.getResponders;
};
console.log("my service is running", $scope.goData, myService);
}]);
You should return promise from getResponders function, & when it gets resolved it should return response.data from that function.
Factory
var myService = angular.module("xo").factory("myService", ['$http', function($http) {
return {
getResponders: function() {
return $http.get('myUrl')
.then(function(response) {
console.log("coming from servicejs", response.data);
//return data when promise resolved
//that would help you to continue promise chain.
return response.data;
});
}
};
}]);
Also inside your controller you should call the factory function and use .then function to get call it when the getResponders service function resolves the $http.get call and assign the data to $scope.gotData
Code
$scope.goData = function(){
myService.getResponders.then(function(data){
$scope.gotData = data;
});
};
This is an example how I did for my project, it work fine for me
var biblionum = angular.module('biblioApp', []);//your app
biblionum.service('CategorieService', function($http) {
this.getAll = function() {
return $http({
method: 'GET',
url: 'ouvrage?action=getcategorie',
// pass in data as strings
headers: {'Content-Type': 'application/x-www-form-urlencoded'} // set the headers so angular passing info as form data (not request payload)
})
.then(function(data) {
return data;
})
}
});
biblionum.controller('libraryController', function($scope,CategorieService) {
var cat = CategorieService.getAll();
cat.then(function(data) {
$scope.categories = data.data;//don't forget "this" in the service
})
});

Is there a way I can return a promise from a $resource without needing to use $q?

I have coded the following service:
angular.module('App')
.factory('TestService', ['$http', '$q', '$resource', function (
$http, $q, $resource) {
var TestResource = $resource('/api/Tests', {}, {
saveData: { method: 'PUT' },
deleteData: { method: "DELETE", params: { TestId: 0 } }
});
var factory = {
query: function (selectedSubject) {
var deferred = $q.defer();
TestResource.query({ subjectId: selectedSubject },
function (resp) {
deferred.resolve(resp);
}
);
return deferred.promise;
//return Test.query({ subjectId: selectedSubject });
}
}
return factory;
}]);
In my controller I am calling it this way:
TestService.query($scope.selectedSubject)
.then(function (result) {
$scope.gridData = result;
}, function (result) {
alert("Error: No data returned");
});
Is there a way that I could cut out a few lines of code by not having $q in my service. Is there a way that I could return a promise from the $resource? I have tried the commented out code but that gives me an error saying there is no ".then" method.
$resource can't return a promise in the current stable version of Angular (1.0.8), but it looks like it'll come in version 1.2. It was added in v1.1.3 (v 1.1 is the unstable branch):
$resource: expose promise based api via $then and $resolved (dba6bc73)

Resources