I'm trying to display a date that I'm getting from a server, I'm able to retreive it and display it correctly in the service but in my controller it's undefined would you help me to get this fixed.
here is my service
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function() {
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
console.log('response', response)
statusDate.Date = $filter('date')(
new Date(response.Date), dateFormat);
console.log('Date', statusDate.Date)
return statusDate.Date;
});
};
return statusDate;
};
and in my controller
function footerController($scope,footerService) {
$scope.myDate = footerService.getStatusDate();
console.log('$scope.myDate', $scope.myDate);
};
You can use $q.defer :
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function() {
var deferred = $q.defer();
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
statusDate.Date = $filter('date')(
new Date(response.Date), dateFormat);
deferred.resolve(statusDate.Date );
});
return deferred;
};
return statusDate;
};
And then:
footerService.getStatusDate()
.then(function(data) {
$scope.myDate = data;
});
function footerService($http, $filter) {
return {
getStatusDate = function() {
return $http.get(_contextPath + '/getDate', {});
}
};
}
function footerController($scope, footerService) {
$scope.myDate;
footerService.getStatusDate().then(function(response){
$scope.myDate = response.data.Date;
}).catch(function(response){
//error
});
}
Using $http means using async Promises.
You can define what happens when the async call is successful using then :
footerService.getStatusDate()
.then(function(receivedDate) {
$scope.myDate = receivedDate;
console.log('$scope.myDate', $scope.myDate);
});
Plus don't forget the return in getStatusDate (return $http.get...).
More info about async Promises : https://docs.angularjs.org/api/ng/service/$q
Since .success(function(){}) is the callback so you can not return any value from there. The best solution for it to pass one successCallback from controller to getStatusDate and pass the expected response from .success(function(response){}) to successCallback.
By doing this you will be able to get the service response in your controller.
Code is attached below:
function footerService($http,$filter) {
var dateFormat = 'yyyy-MM-dd';
var statusDate = {};
statusDate.getStatusDate = function(successCallback) {
$http.get(_contextPath + "/getDate", {}).success(
function(response) {
successCallback($filter('date')(new Date(response.Date), dateFormat));
});
};
return statusDate;
};
function footerController($scope, footerService) {
function successCallback(res) {
$scope.myDate = res;
console.log('$scope.myDate', $scope.myDate);
}
footerService.getStatusDate(successCallback);
};
In the service you need to return the promise from the $http request.
Try:
function footerService('$http', [$http]) {
var statusDate = {};
getStatusDate = function() {
return $http.get(_contextPath + "/getDate", {})
};
return {
getStatusDate: getStatusDate
};
};
And your controller like this:
function footerController($scope,footerService) {
footerService.getStatusDate().then(function(results) {
$scope.myDate = results.data;
});
$scope.$watch(function() {return $scope.myDate;}, function() {
console.log('$scope.myDate', $scope.myDate);
});
};
And you would apply your filter logic in the .then() method in the controller.
Related
This is the service where im saving the data and returning the result
nurseService.js
(function () {
'use strict';
angular.module('app.services')
.factory('NurseService', NurseService);
NurseService.$inject = ['$http', '$q','Constants'];
function NurseService($http, $q, Constants){
var service = {
saveSample:saveSample
};
return service;
function saveSample(data) {
var deferred = $q.defer();
$http({method:"POST", data:data, url:Constants.API_URL_SAVE_SAMPLE_COLLECATION}).then(function(result){
return deferred.resolve(result.data);
});
};
return deferred.promise;
}
})();
This is the controller where im using the return value and based on the value returned im calling another http get method and printing it.
vm.saveSamples = function() {
var data = {
visitId: visitId,
orders: vm.gridTestApi.selection.getSelectedRows()
};
var url = Constants.API_URL_SAVE_SAMPLE_COLLECATION;
var barCodeResponse = null;
var sampleId = "";
var myDataPromise = NurseService.saveSample(data);
myDataPromise.then(function(result) {
console.log("data.name"+ JSON.stringify(result));
vm.printBarCode(result.sampleId);
// if(sampleId != ""){
printElement("printThisElement");
// }
});
//Barcode method this should call after saving the data and returned the sampleId
vm.printBarCode = function(sampleId) {
$http.get("master/barcode/"+sampleId).then(function (response) {
vm.barCodeImage = angular.copy(response.data.result);
});
}
But here before the saving print is calling. How can I hadle so that the first call should finish before the second http call to barcode and print it
//Print code
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function () {
printSection.innerHTML = '';
}
};
You have to return the $http call in printBarCode and use a .then like so:
//Barcode method this should call after saving the data and returned the sampleId
vm.printBarCode = function(sampleId) {
return $http.get("master/barcode/"+sampleId).then(function (response) {
vm.barCodeImage = response.data.result;
});
}
myDataPromise.then(function(result) {
console.log("data.name"+ JSON.stringify(result));
return vm.printBarCode(result.sampleId)
}).then(
function() {
printElement("printThisElement");
},
function(error) {
// error handler
}
);
printElement will now wait for the printBarCode promise and .then to fulfil before executing.
You also don't have to use a $q.defer when doing a $http call, $http is already a promise so you can just return that like so:
function saveSample(data) {
return $http({method:"POST", data:data, url:Constants.API_URL_SAVE_SAMPLE_COLLECATION})
.then(
function(result) {
return result.data;
},
function(error) {
// don't forget to handle errors
}
);
}
First of all, $http internally implements promises you you dont have to explicitly create them.
Secondly, you should put all your http requests in the service/factory
The modified code looks like
angular.module('app.services')
.factory('NurseService', function($http){
var service = {
saveSample : function(data){
//first http implementation here
return $http.post(....);
}
getBarcode : function(sampleId){
//http implementation here for barcode
return $http.get(....);
}
}
return service;
});
and your controller can use the service like
angular.module('app.services')
.controller('saveSampleCtrl',function($scope,NurseService){
var postData = {
//your post data here
}
NurseService.saveSample(postData)
.then(function(data){
//read sampleId here from data
var sampleId = data.sampleId;
NurseService.getBarcode(sampleId)
.then(function(){
//your print statement here
});
});
}
there might be typos in the code but this is just a basic idea on how you could do that. Hope it helps
I have an Angular service that looks like this:
(function () {
'use strict';
var serviceId = 'currentUserService';
angular.module('app').factory(serviceId, ['common', 'datacontext', currentUserService]);
function currentUserService(common, datacontext) {
var $q = common.$q;
var getLogFn = common.logger.getLogFn;
var logError = getLogFn(serviceId, "error");
var user = {};
var service = {
user: user,
doesUserHaveFeature: doesUserHaveFeature
};
activate();
return service;
function activate() {
var promises = [getCurrentUser()];
$q.all(promises);
}
function getCurrentUser() {
var deferred = $q.defer();
datacontext.getLoginInformation().then(function (data) {
user = data;
deferred.resolve(data);
});
return deferred.promise;
}
function doesUserHaveFeature(featureName) {
debugger;
var feature = featureName.toLowerCase();
var result = _.filter(user.features, function(item) {
var featureString = item.toLowerCase();
return feature == featureString;
});
if (result) {
return true;
}
return false;
}
}
})();
The service is injected into my Controller and my controller calls the doesUserHaveFeature() method.
However, the doesUserHaveFeature method is called before the promise in the activate method is resolved. Therefore, the user variable is still an empty object.
How can I ensure that the promise in the activate method is returned before the doesUserHaveFeature method is called?
Thanks!
Jeremy
As the user data is retrieved asynchronously, your factory methods are going to have to return promises. Here's how I'd do it...
.factory('currentUserService', function(datacontext) {
var userPromise = datacontext.getLoginInformation();
return {
user: userPromise,
doesUserHaveFeature: function(featureName) {
return userPromise.then(function(user) {
return _.some(user.features, function(feature) {
return feature.toLowerCase() === featureName.toLowerCase();
});
});
}
};
});
Controller 1
var promise = UserService.userexists(groupid);
promise.then(
},
function (response) {
}
);
Controller 2
var promise = UserService.userexists(groupid);
promise.then(
},
function (response) {
}
);
Service
app.factory("UserService", function ($q, $timeout) {
return {
userexists: function (groupid) {
var deferred = $q.defer();
//this is just to keep a pointer to parent scope from within promise scope.
IsCurrentUserMemberOfGroup(groupid, function (isCurrentUser) {
if (isCurrentUser) {
deferred.resolve(isCurrentUser);
}
else {
deferred.reject(isCurrentUser);
}
});
return deferred.promise;
}
}
});
function IsCurrentUserMemberOfGroup(groupId, OnComplete) {
var currentContext = new SP.ClientContext.get_current();
var currentWeb = currentContext.get_web();
var currentUser = currentContext.get_web().get_currentUser();
currentContext.load(currentUser);
var allGroups = currentWeb.get_siteGroups();
currentContext.load(allGroups);
var group = allGroups.getById(groupId);
currentContext.load(group);
var groupUsers = group.get_users();
currentContext.load(groupUsers);
currentContext.executeQueryAsync(OnSuccess, OnFailure);
function OnSuccess(sender, args) {
var userInGroup = false;
var groupUserEnumerator = groupUsers.getEnumerator();
while (groupUserEnumerator.moveNext()) {
var groupUser = groupUserEnumerator.get_current();
if (groupUser.get_id() == currentUser.get_id()) {
userInGroup = true;
break;
}
}
OnComplete(userInGroup);
}
function OnFailure(sender, args) {
OnComplete(false);
}
}
I have controller 1 and controller 2 on the same page, both use the same service to check the user exist in a specific group. Problem is the service runs the check user method (IsCurrentUserMemberOfGroup) for each controller. Is there a way so that I execute the method once and other controllers can use it?
This is a sharepoint 2010 environment.
Thanks
You could cache the result in your service, maybe something like
app.factory("UserService", function ($q, $timeout) {
return {
var cache = {};
userexists: function (groupid) {
var deferred = $q.defer();
if (cache[groupif]) {
deferred.resolve(cache[groupif]);
return deferred.promise;
}
IsCurrentUserMemberOfGroup(groupid, function (isCurrentUser) {
if (isCurrentUser) {
cache[groupif] = isCurrentUser;
deferred.resolve(isCurrentUser);
}
else {
deferred.reject(isCurrentUser);
}
});
return deferred.promise;
}
}
});
I've refactored my code so that all model creation is off the controller and inside my factory. This works great but now I want to make sure that on init that all my promises are resolved in order and so attempting to use $q.all returns an array of undefined items. What am I doing wrong? Here is my code:
//Data 1
{'name': 'a name'}
//Data 2
{'city': 'a city'}
//Data 3
{'car' : 'a car'}
var app = angular.module('app', []);
app.service('myHttpService', ['$http', '$q', function($http, $q){
var DEFAULT_ERROR = "An error occurred while contacting the server.";
return {
myPromise : function(httpAction){
var deferred = $q.defer();
httpAction.success(function(data){
deferred.resolve(data);
}).error(function(reason){
if(reason) {
if(typeof reason === 'object' && reason.err)
deferred.reject(reason.err);
else if(typeof reason === 'string')
deferred.reject(reason);
else
deferred.reject(DEFAULT_ERROR);
}
else
deferred.reject(DEFAULT_ERROR);
});
return deferred.promise;
}
}
}]);
app.factory('myService', function($http, $q, myHttpService) {
return MyData = {
getData1: getData1,
getData2: getData2,
getData3: getData3,
getAllData: getAllData
};
function getData1() {
return myHttpService.apiPromise($http.get('/api/data_1')).then(function(data1){
MyData.data1 = data1;
});
}
function getData2() {
return myHttpService.apiPromise($http.get('/api/data_2')).then(function(data2) {
MyData.data2 = data2;
});
}
function getData3(){
return myHttpService.apiPromise($http.get('/api/data_3')).then(function(data3) {
MyData.data3 = data3
});
}
function getAllData(promises) {
return $q.all(promises).then(function(data) {
MyData.allData = data;
})
}
});
app.controller('MyCtrl', function (myService) {
var this = self;
this.data1 = myService.getData1;
this.data2 = myService.getData2;
this.data3 = myService.getData3;
this.allData = myService.getAllData;
this.init = function() {
//HOW DO I GET THIS
myService.getData1().then() {
self.data1 = myService.data1;
myService.getData2().then() {
self.data2 = myService.data2;
myService.getData3().then {
self.data3 = myService.data3;
}
}
}
// INTO THIS??
myService.getAllData([myService.getData1(), myService.getData2(), myService.getData3()]).then(function() {
self.allData = myService.getAllData;
console.log(self.allData);
//EXPECT [{'name': 'my name'},{'city': 'my city'},{'car' : 'my car'}]
//INSTEAD GET
//[undefined, undefined, undefined]
})
}
});
In your case myService.getDataN() is not a promise. Every getDataN should also return data inside then.
...
function getData1() {
return myHttpService.apiPromise($http.get('/api/data_1')).then(function(data1){
MyData.data1 = data1;
return data1;
});
}
...
I have a factory which get data from server. In the factory method I have used $cacheFactory to cache getting data. My code is as follows..
var buyersService = function ($http, $q,$cacheFactory) {
var serviceBase = '/api/OMData/';
var BuyersFactory = {};
buyersService.cache = $cacheFactory('cacheId');
BuyersFactory.GetBuyers = function () {
var dataList = buyersService.cache.get('BuyerData');
if (dataList != null && dataList.length > 0) {
return dataList;
}
else {
return $http.get(serviceBase + 'GetBuyers').then(
function (results) {
buyersService.cache.put("BuyerData", results.data);
return results.data;
});
}
}
app.factory('OMDataService', ['$http', '$q', '$cacheFactory', buyersService]);
});
Now I have called GetBuyers method from controller. My method is like below..
var BuyerController = function ($scope, BuyersService) {
$scope.Buyers = [];
init();
function init() {
getBuyers();
}
function getBuyers() {
BuyersService.GetBuyers()
.then(function (data) {
$scope.Buyers = data;
}, function (error) {
alert(error.message);
});
}
};
app.register.controller('BuyersController', ['$scope', 'OMDataService', BuyerController]);
When I have executed my controller method second time I have got an error message in promise part.
Object doesn't support property or method 'then'
The issue here is that your function returns two different things: either a promise or plain data. To remedy this, use another promise to control the flow and return that one as the result of the function.
Update your code to
var buyersService = function ($http, $q,$cacheFactory) {
var serviceBase = '/api/OMData/';
var BuyersFactory = {};
buyersService.cache = $cacheFactory('cacheId');
BuyersFactory.GetBuyers = function () {
var buyersDataIsAvailable = $q.defer();
var dataList = buyersService.cache.get('BuyerData');
if (dataList != null && dataList.length > 0) {
buyersDataIsAvailable.resolve(dataList);
}
else {
$http.get(serviceBase + 'GetBuyers').then(
function (results) {
buyersService.cache.put("BuyerData", results.data);
buyersDataIsAvailable.resolve(results.data);
});
}
return buyersDataIsAvailable.promise;
}
app.factory('OMDataService', ['$http', '$q', '$cacheFactory', buyersService]);
});