I'm trying to create a function that returns a promise and inside that function I have an angular.forEach that returns a promise.
Here is an example code:
function func1() {
func2(demoText, demoObject).then(function(response) {
console.log(response);
});
}
function func2(demoText, demoObject) {
var deferred = $q.defer();
var returnString = "someReturnString";
var keepGoing = true;
var loopPromises = [];
angular.forEach(demoObject, function(value, key) {
if(keepGoing) {
var deferred2 = $q.defer();
loopPromises.push(deferred2.promise);
if(value.type == 'other') {
someService.getDataFromServer()
.then(function(serverResponse) {
returnString = serverResponse;
deferred2.resolve();
});
keepGoing = false;
}
else {
deferred2.resolve();
}
}
});
return $q.all(loopPromises).then(function () {
deferred.resolve(returnString);
return deferred.promise;
});
}
Now the returned value is "someReturnString" which means that the value is retuned before I'm getting the result from the server.
How can this be resolved?
Related
I am trying to write a memoization function, but keep getting the following error.
Error - "TypeError: getNthFibonacciNo is not a function
at dabebimaya.js:28:38
at https://static.jsbin.com/js/prod/runner-4.1.4.min.js:1:13924
at https://static.jsbin.com/js/prod/runner-4.1.4.min.js:1:10866"
How can I find this error in my code? I have tried googling the error with no avail. Please point out any additional errors too if possible.
function memoize(fn) {
var cache = {};
if (cache[arguments[0]]!==undefined) {
return cache[arguments[0]];
}
else {
var value = fn.apply(this, arguments);
cache[arguments[0]] = value;
return value;
}
}
var getNthFibonacciNo = memoize(function(n){
//1,1,2,3,5,8,13,21,34
if(i<=2)
return 1;
var fib = [0,1,1];
for(var i=3;i<=n;i++) {
fib[i] = fib[i-2]+fib[i-1];
}
return fib[n];
});
console.log(getNthFibonacciNo(7));
Your memoize function isn't returning a function.
function memoize(fn) {
var cache = {};
return function() {
if (cache[arguments[0]]!==undefined) {
return cache[arguments[0]];
}
else {
var value = fn.apply(this, arguments);
cache[arguments[0]] = value;
return value;
}
}
}
now returns a function so that it can be called multiple times.
Usage
function test(a) {
console.log('calling test', a);
return a + 1;
}
const memoized = memoize(test);
memoized(1); // prints calling test and returns 2
memoized(1); // returns 2
memoized(2); // prints calling test and returns 3
I managed to fix my code after suggestions by AnilRedshift. Below is the fixed code.
function memoize(fn) {
var cache = {};
return function() {
var key = JSON.stringify(arguments);
if (cache[key]) {
console.log('cache used');
return cache[key];
}
else {
var value = fn.apply(this, arguments);
cache[key] = value;
console.log('cache not used');
return value;
}
};
}
var fibonacciMemoized = memoize(function(n) {
//1,1,2,3,5,8,13,21,34
if(i<=2)
return 1;
var fib = [0,1,1];
for(var i=3;i<=n;i++) {
fib[i] = fibonacciMemoized(i-2)+fibonacciMemoized(i-1);
}
return fib[n];
});
console.log(fibonacciMemoized(7));
console.log(fibonacciMemoized(9));
How to pass data from promise then method to an object method.
this.httpReq(url).then(function (data) {
this.storeData(data);
});
I know that here I'm out of scope and this doesn't refer to my object. But, nevertheless, I can't understand how to resolve it.
Bellow you can find entire code snippet. In the end, I want to get data from the service API and store it in the object array property this.storage.
var http = require('http');
function CoubApi (url) {
this.url = url;
this.storage = [];
this.httpReq = httpReq;
this.searchData = searchData;
this.storeData = storeData;
}
function httpReq (url) {
var promise = new Promise (function (resolve, reject) {
http.get(url, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
if(data.length > 0) {
resolve(JSON.parse(data));
} else {
reject("Error: HTTP request rejected!");
}
});
}).on('error', function (err) {
console.log("Error: ", e);
});
});
return promise;
}
function storeData (data) {
var i;
console.log("Storrrreee");
for(i = 0; i < 10; i++) {
this.storage.push(data.coubs[i]);
}
}
function searchData (searchtext, order, page) {
var url = this.url+
"search?q="+searchtext+
"&order_by="+order+
"&page="+page;
this.httpReq(url).then(function (data) {
this.storeData(data);
});
}
var coub = new CoubApi("http://coub.com/api/v2/");
coub.searchData("cat", "newest_popular", 1);
console.log(coub.storage);
You can store this in varaible:
var self = this;
this.httpReq(url).then(function (data) {
self.storeData(data);
});
or use bind:
this.httpReq(url).then(function (data) {
this.storeData(data);
}.bind(this));
I am recovering all data in allEnquetes. I just find the requested this list, but an error occurs because the allEnquetes returns a promise.
.factory('enquetesAPI', function($http,myConfig){
return {
allEnquete: function(){
return $http.get(myConfig.remote + '/lists.asp?acao=list-enquete&codadmin='+myConfig.codadmin);
},
getEnquete: function(enqueteId) {
for (var i = 0; i < this.allEnquete().length; i++) {
if (this.allEnquete()[i].codigo === parseInt(enqueteId)) {
return this.allEnquete()[i];
}
}
return this.allEnquete()
}
};
})
This is the result when I console.log ( this.allEnquete )
allEnquetes returns a promise so you just can't loop through that. Check below code. I have not tested it. but this should give you some idea on how you should ideally be doing this.
.factory('enquetesAPI', function($http, $q, myConfig){
return {
allEnquete: function(){
console.log('called');
return $http.get(myConfig.remote + '/lists.asp?acao=list-enquete&codadmin='+myConfig.codadmin);
},
getEnquete: function(enqueteId) {
var deferred = $q.defer();
this.allEnquete().then(function(enquetes){
var returnVal = enquetes;
for (var i = 0; i < enquetes.length; i++) {
if (this.allEnquete()[i].codigo === parseInt(enqueteId)){
returnVal = enquetes[i];
}
}
deferred.resolve(returnVal);
}, function(errorResponse){
deferred.reject(errorResponse);
});
return deferred.promise;
}
};
});
and this is how you should be using your service.
enquetesAPI.getEnquete(id).then(enquetes){
// do whatever you need to do
}
I am trying to bind a variable to a scope before it moves to the view but my view shows before the variable is bounded. Here is my code.
$scope.getListing = function() {
var deferred = $q.defer();
$scope.$applyAsync(function() {
$rootScope.listingDetails =[];
referralCasesGroupByCaseStatus.getListing($rootScope.userDetails.rows.item(2).value).then(function(data){
$rootScope.listingDetails = data
deferred.resolve($rootScope.listingDetails)
if($rootScope.fromDashboard === false) {
$scope.showCaseStatus(1);
$state.go('app.case_status')
}
else {
$scope.showCaseStatus($rootScope.statusNumber)
$state.go('app.case_status')
$ionicLoading.hide();
}
});
})
return deferred.promise;
};
var changedNumber = 0;
$scope.showCaseStatus = function(number) {
var finishedPushingListings = false;
$rootScope.listingByCaseStatus = [];
$rootScope.caseStatusListings = [];
if(changedNumber !== 0 && changedNumber !== number) {
changedNumber = number;
}
else {
if(changedNumber > 0) {
$scope.$applyAsync($rootScope.detailsPresent = true);
}
}
$scope.$applyAsync(function() {
angular.forEach($rootScope.listingDetails, function(value, key) {
if(value.real_estate_agent_assignment_status_id == number) {
$rootScope.listingByCaseStatus.push(value);
}
});
})
$scope.$applyAsync(function() {
if($rootScope.listingByCaseStatus == 0 || $rootScope.listingByCaseStatus == undefined || $rootScope.listingByCaseStatus == null) {
$rootScope.detailsPresent = true;
$rootScope.changeNumber = true;
finishedPushingListings = true;
}
else {
$rootScope.detailsPresent = false;
$scope.noMoreItemsAvailable = false;
$rootScope.changeNumber = true;
finishedPushingListings = true;
}
})
};
The main problem here is that the function $scope.showCaseStatus($rootScope.statusNumber) doesnt finish executing before it executes the $state.go('app.case_status') and i would like for it to wait and finish executing before it jumps to the $state.go('app.case_status').
Any help is appreciated.
Since you are using $applyAsync(), the function effects are asynchronous. One way to achieve what you want is to make showCaseStatus() return a promise - and take into account that there are 2 asynchronous blocks:
$scope.showCaseStatus = function(number) {
var ..., d1, d2;
...
d1 = $q.defer();
$scope.$applyAsync(function() {
angular.forEach($rootScope.listingDetails, function(value, key) {
...
});
d1.resolve();
})
d2 = $q.defer();
$scope.$applyAsync(function() {
...
d2.resolve();
})
// both promises must be resolved to continue
return $q.all([d1.promise, d2.promise]);
};
Then the caller becomes:
$scope.showCaseStatus($rootScope.statusNumber).then(function() {
$state.go('app.case_status')
$ionicLoading.hide();
});
Some notes:
If you do not need the async blocks, you can remove them and simplify the code
If the second async block relies on the result of the first, they too should be synchronized
I have the following code and in the code when I enter inside the if statement (if (that.cont) ) I get an error of a un-finished promise chain, what can be the reason for this and how should I avoid it?
run: function() {
var oDef = Q.defer();
var Obj = Q(sWUrl);
if (that.cont) {
Obj = that.cont.get(that.cont.transl).then(function(mSet) {
debugger;
if (mSet) {
var lang = mSet.supportedLang;
var dft = mSet.defaultLang;
if (!dft) {
if (lang) {
dft = lang.split(",")[1];
} else {
dft = "en";
}
}
return Q(sWUrl + "&lang=" + window.encodeURIComponent(lang));
} else {
return Q(sWUrl);
}
}, function() {
return Q(sWUrl);
}).then(function(sUri) {
return that.cont.se.pre.get("Pre").then(function(oPreSet) {
return sUri + "&device=" + window.encodeURIComponent(oPreSet.dte);
}).fail(function(error) {
return sUri;
});
});
}
return Obj.then(function(sUri) {
oWin.window.location.href = sUri;
return oWin.oDef.promise;
});
},
I don't know where that error would be coming from, but one thing is for sure - whatever you return from run is never going to resolve, because you never resolve oDef (and you are using the "deferred antipattern").
You also seem to be mistakenly under the assumption that you have to return a promise from your handlers (although you are forgetting to do this in one place), but this is not true. You can just return ordinary values if there's nothing to await.
Give this a try:
run: function() {
var p;
if (that.cont) {
p = that.cont.get(that.cont.transl).then(function(mSet) {
if (mSet) {
var lang = mSet.supportedLang;
var dft = mSet.defaultLang;
if (!dft) {
if (lang) {
dft = lang.split(",")[1];
} else {
dft = "en";
}
}
return sWUrl + "&lang=" + window.encodeURIComponent(lang);
} else {
return sWUrl;
}
}, function() {
return sWUrl;
}).then(function(sUri) {
return that.cont.se.pre.get("Pre").then(function(oPreSet) {
return sUri + "&device=" + window.encodeURIComponent(oPreSet.dte);
}).fail(function(error) {
return sUri;
});
});
} else {
p = Q(sWUrl);
}
return p.then(function(sUri) {
oWin.window.location.href = sUri;
});
},