how to synchronous call in controller using angularjs - angularjs

services.js:
mPortalServices.factory('ChannelTypeService', ['$filter', '$http', '$q', function (filter, $http, $q) {
var ChannelTypeService = {};
ChannelTypeService.getAll = function () {
var defered = $q.defer();
$http.get('jsondata/ChannelType.json').then(function(response){
defered.resolve(response.data);
});
return defered.promise;
}
ChannelTypeService.getSingle2 = function (typeId) {
var defered = $q.defer();
ChannelTypeService.getAll().then(function(items){
var filtered = filter('filter')(items, {
'TypeId': typeId
});
defered.resolve(filtered);
});
return defered.promise;
}
return ChannelTypeService;
}]);
controllers.js:
//some code here...
var firstChannel = channels[0];
ChannelTypeService.getSingle2(firstChannel.ChannelType).then(
function(activities) {
$scope.channelType = activities;
console.log('1111');
console.log($scope.channelType);
} ,
function(reason) { }
);
console.log("2222");
console.log($scope.channelType);
if ($scope.channelType.Type == 1 ) {
$location.path("/list1/");
}
else {
$location.path("/list2/");
}
return;
i want wait result of getSingle2 function, but the code above is asynchronous, how to resolve the question?

Change controllers.js to the following:
function someFunction() {
//some code here...
var deferred = $q.defer();
var firstChannel = channels[0];
ChannelTypeService.getSingle2(firstChannel.ChannelType).then(
function(activities) {
$scope.channelType = activities;
console.log('1111');
console.log($scope.channelType);
console.log("2222");
console.log($scope.channelType);
// the following code will now work:
deferred.resolve();
if ($scope.channelType.Type == 1 ) {
$location.path("/list1/");
}
else {
$location.path("/list2/");
}
} ,
function(reason) { }
);
return deferred.promise;
}
Any code that needs the result of the above function will have to do:
someFunction.then(function() {
// guaranteed to run after, for example, $scope.channelType has been set
})
Like Net205 said, if you want to force getSingle2 to be synchronous, you in general cannot do that.

Related

How to return value from service to controller in Angularjs

i have a service as below
module.service('translationService', [
"$resource",
function($resource) {
var This = this;
This.params = 'HELLO';
This.getTranslation = function() {
var languageFilePath = 'sample.json';
//return languageFilePath;
$resource(languageFilePath).get(function(data) {
var temp = "";
if (This.params != "") {
angular.forEach(data, function(key, value) {
if (value == This.params)
temp = key;
});
} else {
This.translation = "Pls input key";
}
This.translation = temp;
return temp;
});
}
}
]);
In controller i am calling service,
This.translate = translationService.getTranslation();
Problem is when i debug temp has value , but when i return value becomes null. May be its inside one more function .get() and return is losing scope. But if I return languageFilePath as commented above (//return languageFilePath;), value is passing to controller.
Please help me how to return value.
Convert your getTranslation() method to return a promise.
module.service('translationService', [ '$q', '$resource', translationService ]);
function translationService ($q, $resource) {
var This = this;
This.params = 'HELLO';
This.getTranslation = getTranslation;
function getTranslation () {
var deferred = $q.defer(),
languageFilePath = 'sample.json';
$resource(languageFilePath)
.get(_onGetTranslationSuccess, deferred.reject);
function _onGetTranslationSuccess (data) {
var translation;
if (This.params === '') {
deferred.reject('Pls input key');
} else {
angular.forEach(data, function (key, value) {
if (value === This.params) {
translation = key;
}
});
if (angular.isDefined(translation)) {
This.translation = translation;
deferred.resolve(translation);
} else {
deferred.reject('Translation not found');
}
}
}
return deferred.promise;
}
}
You can then consume the promise in your controller and get the translation.
translationService.getTranslation().then(function (translation) {
This.translate = translation;
});
You can handle a variable within the service and then declare a function to retrieve the value from the controler:
.service('translationService', function($q, $http, ...) {
var result= '';
...
function someFunction(...) {
...
result='translation';
...
}
...
return {
getTranslation: function() {return result;}
};
})
On the controller you can do this:
var res = translationService.getTranslation();
You have to return the value from your $resource function.
return $resource(languageFilePath)...

Angularjs async requests

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;
}
}
});

How to make controller wait for service to return a value and how to access the returned value in controller?

I am new to angularjs. I am having trouble in accessing value that is returned from angularjs service in its controller.
Following is the code in controller:
'use strict';
app.controller('AdminTaskCtrl', function ($scope, Search) {
$scope.buildEnquiry = function (collegeId, ) {
Search.getIdByEmail(collegeId).then ( function ( result ) {
$scope.uId = result;
console.log($scope.uId);
});
};
});//controller ends here
And the code in Search service is as follows:
'use strict';
app.factory('Search',function ($firebase, FIREBASE_URL, $rootScope) {
var simpleuser = "";
getIdByEmail: function(counsellorEmail) {
var collegeuserArray = ($firebase(new Firebase(FIREBASE_URL+"abc/def/")).$asArray());
collegeuserArray.$loaded(function(collegeuserArray) {
for(var i=0; i<collegeuserArray.length; i++)
{
if((collegeuserArray[i].$value) == counsellorEmail)
{
simpleuser = collegeuserArray.$keyAt(collegeuserArray[i]);
console.log(simpleuser);
return simpleuser;
}
}
}, function(error) {
console.error("Error:", error);
});
}
};
);//service ends here.
When the code executes it gives error for .then function as fallows:
TypeError: undefined is not a function and value in controller is not accessed.
Please help.
'use strict';
app.factory('Search',function ($firebase, FIREBASE_URL, $rootScope, $q) {
var simpleuser = "";
getIdByEmail: function(counsellorEmail) {
var deferred = $q.defer();
var collegeUserArray = ($firebase(new Firebase(FIREBASE_URL+"abc/def/")).$asArray());
collegeUserArray.$loaded(function(collegeUserArray) {
for(var i=0; i<collegeUserArray.length; i++)
{
if((collegeUserArray[i].$value) == counsellorEmail)
{
simpleUser = collegeUserArray.$keyAt(collegeUserArray[i]);
console.log(simpleUser);
//return simpleUser;
deferred.resolve(simpleUser);
}
}
}, function(error) {
console.error("Error:", error);
deferred.reject(error);
});
return deferred.promise;
}
};
);
And your controller
'use strict';
app.controller('AdminTaskCtrl', function ($scope, Search) {
$scope.buildEnquiry = function (collegeId, ) {
Search.getIdByEmail(collegeId).then ( function ( result ) {
$scope.uId = result;
console.log($scope.uId);
}, function(error){
//If an error happened, handle it here
});
};
});
To directly answer your question, $loaded returns a promise, so the simplest answer here would be to return it from your service instead of bothering with $q and all these other things.
It does seem like the whole premise here is flawed and that this is an XY problem. It seems like several hacks intended to subvert the intended usage of these libs, and like a good, solid read of the Angular walkthrough and the AngularFire guide would save a lot of pain and needless complexity here.
The use of factory here is a subversion and heavily coupled. The syntax is invalid and wouldn't compile. And ultimately, the goal is to add a search method to the synchronized array returned from AngularFire, which should be done with $extendFactory.
app.factory('firebaseRef', function(FIREBASE_URL) {
return function(path) {
var ref = new Firebase(FIREBASE_URL);
if( path ) { ref = ref.child(path); }
return ref;
}
});
app.factory('SearchableArray', function($firebase, $FirebaseArray) {
var ArrayWithSearch = $FirebaseArray.$extendFactory({
searchByEmail: function(emailAddress) {
var res = null;
for(var i=0, len=this.$list.length; i < len; i++ ) {
if( this.$list[i].email === emailAddress ) {
res = this.$list[i];
break;
}
}
return res;
}
});
return function(ref) {
return $firebase(ref, {arrayFactory: ArrayWithSearch}).$asArray();
}
});
app.controller('Controller', function($scope, SearchableArray, firebaseRef) {
$scope.data = SearchableArray( firebaseRef('abc/def') );
$scope.search = function(email) {
console.log( $scope.data.searchByEmail(email) );
};
});

AngularJS $q.all how to resolve data in service and not in controller

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;
});
}
...

How to get data by service and $cacheFactory by one method

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]);
});

Resources