I am not sure how to go about returning the promise. I have tried to return the result in a nested method but would prefer to return the result in two different methods as shown afterwards:
$scope.relatedContacts = function (accountId) {
if (!lodash.isNil(accountId)) {
try {
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function (response) {
return response.data;});
}
}
Would prefer to fix the below example:
$scope.relatedContacts = function (accountId) {
if (!lodash.isNil(accountId)) {
try {
var deferred = $q.defer();
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
return deferred.promise;
}
catch (err) {
$scope.contactsPopulated = false;
}
}
}
$scope.relatedContacts().then(function (response) {
//Some logic here
}
Currently I am getting : "TypeError: Cannot read property 'then' of undefined
"
Thanks all
First of all, remember about consistency. The isNil if makes your function not returning anything in some cases (you will get TypeError: Cannot read property 'then' of undefined " error when accountId is not provided.
You have two ways to solve your problem.
First way:
$scope.relatedContacts = function (accountId) {
return $q(function(resolve, reject) {
if (!lodash.isNil(accountId)) {
try {
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function(response) {
resolve(response.data)
}, reject);
}
catch (err) {
$scope.contactsPopulated = false;
reject(err);
}
}
});
};
The second way (using defer).
$scope.relatedContacts = function (accountId) {
var def = $q.defer();
if (!lodash.isNil(accountId)) {
try {
restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function(response) {
def.resolve(response.data)
}, def.reject);
}
catch (err) {
$scope.contactsPopulated = false;
def.reject(err);
}
}
return def;
};
You should check official reference about $q service:
https://docs.angularjs.org/api/ng/service/$q
There are numerous examples of typical promise usages.
This is what I used to return the value and add additional method to deal with the response.
$scope.relatedContacts = function (accountId) {
var deferred = $q.defer();
if (!lodash.isNil(accountId)) {
try {
deferred.resolve(restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId }));
}
catch (err) {
$scope.contactsPopulated = false;
deferred.reject(err);
}
}
deferred.promise.then(function (response) {
var tests = response;
return $q.when();
},
function () {
console.log("1st reject");
return $q.reject();
});
return deferred.promise;
};
Related
I'm using bluebird in NodeJS. I want to do a nested loop. Something like this:
var Promise = require('bluebird');
funcs.getLatestVideos = function(job, done) {
return Promise.try(function() {
return ProcessRules.getLatestVideos();
})
.then(function(object) {
return ({
'series': ProcessRules.getSeriesRules(),
'videos': object.videos
});
})
.then(function(inputs) {
return Promise.map(inputs.videos, function(video) {
return Promise.map(inputs.series, function(series) {
return Promise.map(series.rules, function(rule) {
return ProcessRules.processRules(video, rule);
});
});
})
})
.then(function(result) {
W.debug("done");
console.log(JSON.stringify(result));
done();
})
.catch(function(err) {
done(err);
W.error("Error occurred ", err.message, err.stack);
});
}
ProcessRules
var Promise = require('bluebird');
var rp = require('request-promise');
var W = require('winston');
var RuleEngine = require('node-rules');
var _ = require('lodash');
funcs.getSeriesRules = function() {
return new Promise(function(resolve, reject) {
var options = {
method: "GET",
uri: API_URL,
// body: status,
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(function(result) {
resolve(result)
})
.catch(function(err) {
reject(err)
});
});
};
funcs.processRules = function(fact, rule) {
return new Promise(function(resolve, reject) {
var rules = [];
var value = new RegExp(rule.value, 'i');
switch (rule.type) {
case 'title':
rules = [{
"condition": function(R) {
// console.log(this.title.match(value));
R.when(this.title.match(value) > -1);
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
case 'desc':
rules = [{
"condition": function(R) {
//console.log(this.desc.match(value));
R.when(this.desc.match(value) > -1);
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
case 'tag':
rules = [{
"condition": function(R) {
// console.log(this.tag.match(value));
R.when(!_.some(this.tags, { 'text': rule.value}))
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
default:
break
};
//initialize the rule engine
const R = new RuleEngine(rules);
//Now pass the fact on to the rule engine for results
R.execute(fact, function(result) {
//console.log(result);
if (result.result) {
resolve(result._id)
}else{
resolve({})
}
});
});
};
It returns me following output
[[[{},{},"58e9d6816961c30367b5154c"],[{}],[],[],[]],[[{},{},"58e9d6816961c30367b5154d"],[{}],[],[],[]]]
But I am expecting with following output:
[58e9d6816961c30367b5154c,58e9d6816961c30367b5154d]
I see some similar question but not getting exact ideas from them.
In getLatestVideos function not able to get done result ,Please help me to resolve this issue.
Please help me to implement nested each loop with bluebird promise.
After long search with multiple questions and answers , I got the answer by Flattening a Promise map.
I don't know exactly its right way but its working for me.
.then(function(inputs) {
return Promise.map(inputs.videos, function(video) {
return Promise.map(inputs.series, function(series) {
return Promise.map(series.rules, function(rule) {
return ProcessRules.processRules(video, rule);
}).reduce(function(prev, cur) {
return cur ? prev.concat(cur) : [];
}, [])
}).reduce(function(prev, cur) {
return prev.concat(cur);
}, [])
}).reduce(function(prev, cur) {
return prev.concat(cur);
}, [])
})
It returns me [58e9d6816961c30367b5154c,58e9d6816961c30367b5154d].
Thanks Everyone.
Trying to access $scope.mySlot.id but it is undefined.
$scope.removeMe = function() {
var shouldRemove = confirm('Remove you from this field trip?');
if (shouldRemove) {
var data = null;
UserService.me().then(function(me){
var data = {userID: me.id, eventID: tripID}
console.log(data);
return data;
}).then (function(data){
var mySlot = GreenTripFilledSlotsFactory.get(data);
return mySlot;
}).then (function(mySlot) {
$scope.mySlot = mySlot;
console.log("this is $scope.mySlot: ");
console.log($scope.mySlot); //this shows up as a resource with proper values
console.log("this is $scope.mySlot.id: ")
console.log($scope.mySlot.id); //this is undefined
}).then (function(success){
return $scope.mySlot.$delete(); // this isn't working'
}).then(function(success){
console.log('mySlot deleted');
route.reload();
}).catch(function(error){
console.log(error);
})
}
};
In the console.logs $scope.mySlot is shown as a resource and it does list the values of it. But I'm confused why $scope.mySlot.id is undefined.
FACTORIES:
.factory('GreenTripSlotsFactory', ['$resource', function($resource) {
return $resource('/api/GreenTripSlots/:id/', {id: '#id' }, {
update: {method: 'PUT' }
});
}])
.factory('GreenTripFilledSlotsFactory', ['$resource',
function($resource) {
return $resource('/api/GreenTripSlots/:userID/:eventID/:slotID',
{id: '#id' }, {
update: {method: 'PUT' }
});
}])
BACKEND contollers:
// = /api/GreenTripSlots/:userID/:eventID
router.route('/:userID/:eventID')
.get(function(req,res) {
procedures.procGetSlotByUserAndTrip(req.params.userID,
req.params.eventID).then(function(greenTripUserSlot){
res.send(greenTripUserSlot);
}, function(err) {
console.log(err);
res.sendStatus(500);
})
})
// = /api/GreenTripSlots:/userID/:eventID/:slotID
router.route('/:userID/:eventID/:slotID')
.get(function(req,res) {
procedures.procGetSlotByUserAndTrip(req.params.userID,
req.params.eventID).then(function(greenTripUserSlot){
res.send(greenTripUserSlot);
}, function(err) {
console.log(err);
res.sendStatus(500);
})
})
.delete(function(req, res){
procedures.procRemoveMe(req.params.slotID).then(function(){
res.sendStatus(204);
}, function(err) {
console.log(err);
res.sendStatus(500);
});
})
Backend Procedures:
exports.procGetSlotByUserAndTrip = function(userID, eventID) {
return db.fnRow('procGetSlotByUserAndTrip', [userID, eventID])
}
exports.procRemoveMe = function(slotID) {
return db.fnEmpty('procRemoveMe', [slotID])
SQL Stored Procedure for Get:
CREATE DEFINER=`CharleyHannah`#`localhost` PROCEDURE
`procGetSlotByUserAndTrip`(pUserId INT, pEventId INT)
BEGIN
SELECT *
FROM userEvents u
WHERE u.userID = pUserId & u.eventID = pEventId;
END
SQL Stored Procedure for delete:
CREATE DEFINER=`CharleyHannah`#`localhost` PROCEDURE
`procRemoveMe`(pSlotId int)
BEGIN
DELETE
FROM userEvents
WHERE id = pSlotId;
END
Your function GreenTripFilledSlotsFactory.get(data); returns a promise. You can write something like that:
var _promise = GreenTripFilledSlotsFactory.get(data);
_promise.then(function(res) {
$scope.mySlot = res;
console.log($scope.mySlot.id); //should display your value now
});
In the res Variable your object is stored.
You assign userToRemove outside the promise then and it's executed before $scope.ME assingning.
Instead of using the factories, I had success in just using $http.get and $http.delete requests:
$scope.removeMe = function() {
var shouldRemove = confirm('Remove you from this field trip?');
if (shouldRemove) {
var data = null;
UserService.me().then(function(me){
var data = {eventID: tripID, userID: me.id}
console.log(data);
return data;
}).then (function(data){
var mySlot = $http.get('/api/GreenTripSlots/' + data.eventID + '/' + data.userID);
console.log(mySlot);
return mySlot;
}).then (function(mySlot) {
var slotToDelete = mySlot.data;
console.log(slotToDelete);
console.log(slotToDelete.id)
return slotToDelete;
}).then (function(slotToDelete){
var slotID = slotToDelete.id;
$http.delete('/api/GreenTripSlots/delete/' + slotID);
console.log('deleted successfully')
$route.reload();
}).catch(function(error){
console.log(error);
})
}
};
}])
I have implemented a promise inside the factory which seems to work. However I seem to be returning the function ... not the product of the function. If I console log I am seeing the full function printed out in the console instead of the data.
Have I messed up the way the data is return?
Object {data: function} <-- from console log
latestScores.factory('importIO', function($q) {
return {
data: function(){
var deferred = $q.defer()
setTimeout(function() {
var io2 = new importio("xxx", "xxx", "import.io");
io2.connect(function(connected) {
if (!connected) {
console.error("Unable to connect");
return;
}
var data;
var callback = function(finished, message) {
if (message.type == "DISCONNECT") {
console.error("The query was cancelled as the client was disconnected");
deferred.reject(new Error('No name specified for greeting'))
}
if (message.type == "MESSAGE") {
if (message.data.hasOwnProperty("errorType")) {
console.error("Got an error!", message.data);
} else {
data = message.data.results;
deferred.resolve(data)
}
}
if (finished) {
data = message.data.results;
deferred.resolve(data)
}
};
io2.query({
"connectorGuids": [
"xxx"
],
}, callback);
});
}, delay)
return deferred.promise
}
}
});
latestScores.controller('ScoresController', function($scope, importIO) {
$scope.liveScores = importIO.data;
console.log($scope.liveScores); /* returns a console log of function not data */
});
Thanks for your time.
You are assigning the function to $scope.liveScores not the result.
You make use of promises like this:
importIO.data().then(function(result){
$scope.liveScores = result;
console.log($scope.liveScores);
});
This means you execute data function and then, after the method "data" is complete, you assign the result to liveScores.
Since importIO.data() is a function..try this:
latestScores.controller('ScoresController', function($scope, importIO) {
importIO.data().then(function (result) {
$scope.liveScores = result;
console.log($scope.liveScores);
});
I have many $http requests as following:
Scholarship.loadMaxAcademicYear().success(function (AcademicYearId) {
if (AcademicYearId) {
Scholarship.deleteAllCurrentData(data).success(function () {
Scholarship.copyDataToCurrentYear().success(function(){
Scholarship.getPromises(null, AcademicYearId).then(function () {
$scope.isSuccess = true;
$timeout(function () {
$scope.isSuccess = false;
$scope.isSubmit = false;
$scope.confirmModal.close();
}, 5000);
}, function(err){
importError();
});
}).error(function(){
importError();
})
}).error(function(){
importError();
});
}
}).error(function (err) {
importError();
});
I want to reduce the error callback to be only one at the end as following:
Scholarship.loadMaxAcademicYear().success(function (AcademicYearId) {
if (AcademicYearId) {
Scholarship.deleteAllCurrentData(data).success(function () {
Scholarship.copyDataToCurrentYear().success(function(){
Scholarship.getPromises(null, AcademicYearId).then(function () {
$scope.isSuccess = true;
$timeout(function () {
$scope.isSuccess = false;
$scope.isSubmit = false;
$scope.confirmModal.close();
}, 5000);
}
})
})
}
}).error(function (err) {
importError();
});
I'm thinking of using the async but Angular might have some way to handle this kind of problem. Would it be possible to do so in AngularJs?
You've still got a pyramid of doom even in your second example. The key here is to use the .then() method to allow promise chaining:
Scholarship.loadMaxAcademicYear().then(function(response) {
var academicYearId = response.data;
if (academicYearId) {
return Scholarship.deleteAllCurrentData(academicYearId)
.then(function() {
return Scholarship.copyDataToCurrentYear();
}).then(function() {
return Scholarship.getPromises(null, academicYearId);
}).then(function() {
$scope.isSuccess = true;
return $timeout(function() {
$scope.isSuccess = false;
$scope.isSubmit = false;
$scope.confirmModal.close();
}, 5000);
});
}
}).catch(function(err) {
importError();
});
We can also shorten this a bit by using .bind():
Scholarship.loadMaxAcademicYear().then(function(response) {
var academicYearId = response.data;
if (academicYearId) {
return Scholarship.deleteAllCurrentData(academicYearId)
.then(Scholarship.copyDataToCurrentYear.bind(Scholarship))
.then(Scholarship.getPromises.bind(Scholarship, null, academicYearId))
.then(function() {
$scope.isSuccess = true;
return $timeout(function() {
$scope.isSuccess = false;
$scope.isSubmit = false;
$scope.confirmModal.close();
}, 5000);
});
}
}).catch(importError);
I am trying to implement a basic function using promises in one of my controllers just so I can ensure it is working correctly before adding in more complex functionality. I am getting a "TypeError: undefined is not a function" on the ".then(function(data){" in the lockPromise method.
Function called from view
$scope.lockPromise = function(fieldId) {
$scope.getLockMessage2(fieldId).getWeather()
.then(function(data) {
if (data === "returned SUCCESS info") {
alert("data is good");
} else {
alert("FAILED");
}
}, function(error) {
alert(error);
});
};
Second function in ctrl
$scope.getLockMessage2 = function(fieldId) {
return{
getWeather: function() {
return $http.get('/api/getData')
.then(function(response) {
if (typeof response.data === "string") {
return response.data;
} else {
return $q.reject(response.data);
}
}, function(response) {
return $q.reject(response.data);
});
}
};
};
API GET
[Route("api/getData")]
public HttpResponseMessage GetData()
{
string data = JsonConvert.SerializeObject("returned SUCCESS info");
return new HttpResponseMessage
{
Content = new StringContent(data, Encoding.UTF8, "application/json")
};
}
EDIT 1:
code updated to reflect comments
Change
$scope.getLockMessage2(fieldId).then
to
$scope.getLockMessage2(fieldId).getWeather().then
Your $scope.getLockMessage2 return an object, not function.
I think the code should be (not tested):
$scope.lockPromise = function(fieldId) {
$scope.getLockMessage2(fieldId).getWeather()
.then(function(data) {
if (data === "good") {
alert("data is good");
} else {
alert("FAILED");
}
}, function(error) {
alert(error);
});
};