service returns promise but cachingService not - javascript

I am calling the getWeeklyDates which is calling the cachingGlobalConfigurationService which is again calling the globalConfigurationService if the globalConfiguration data could not be found in the localstorage.
The code =>
return cachingGlobalConfigurationService.getGlobalConfiguration()
.then(function(response1){
works fine when the globalConfiguration is not cached yet because then I make the ajax call and return a promise.
But the above line of code with .then(function(response1) is undefined when my globalConfiguration can be found in the localStorage and just this is returned:
else {
return cachedGlobalConfiguration;
}
I guess I can not use .then in this case but I would like.
How can I fix that?
1
this.getWeeklyDates= function (projectId, currentDate) {
return cachingGlobalConfigurationService.getGlobalConfiguration()
.then(function(response1){
// do business logic
});
2
'use strict';
angular.module('test').service('cachingGlobalConfigurationService', function (localStorageService, globalConfigurationService) {
this.getGlobalConfiguration = function () {
var cachedGlobalConfiguration = localStorageService.get('globalConfiguration');
if (!cachedGlobalConfiguration) {
return globalConfigurationService.getGlobalConfiguration().then(
function (globalConfiguration) {
localStorageService.set('globalConfiguration', globalConfiguration);
return globalConfiguration;
},
function (error) {
console.log('error', error);
});
}
else {
return cachedGlobalConfiguration;
}
};
this.saveGlobalConfiguration = function (globalConfiguration) {
// TODO: Only save to local storage when service.save was successfully
localStorageService.set('globalConfiguration', globalConfiguration);
globalConfigurationService.saveGlobalConfiguration(globalConfiguration);
}
});
3
'use strict';
angular.module('test').service('globalConfigurationService', function ($http) {
this.getGlobalConfiguration = function () {
// TODO get from db
var path = 'scripts/model/globalConfiguration.json';
return $http.get(path).then(function (response) {
return response.data.globalConfiguration;
});
};
this.saveGlobalConfiguration = function (globalConfiguration) {
// TODO: save on db
//var path = 'scripts/model/globalConfiguration.json';
//return $http.post(path, globalConfiguration).then(function (response) {
// alert('global configuration was saved succesfully!');
//});
}
});

You can inject $q service and use $q.when to wrap the object while returning, so that way you are always returning a promise from your api (and just removed the redundant else). Also remember to reject the promise from catch callback of the promise (if required).
'use strict';
angular.module('test').service('cachingGlobalConfigurationService', function (localStorageService, globalConfigurationService, $q) {
this.getGlobalConfiguration = function () {
var cachedGlobalConfiguration = localStorageService.get('globalConfiguration');
if (cachedGlobalConfiguration) {
//Return a promise
return $q.when(cachedGlobalConfiguration);
}
return globalConfigurationService.getGlobalConfiguration().then(
function (globalConfiguration) {
localStorageService.set('globalConfiguration', globalConfiguration);
return globalConfiguration;
},
function (error) {
console.log('error', error);
return $q.reject(error); //<-- reject
});
};
//....
});
$q.when - Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.

Related

service variable undefined at the time of being accessed in scope

I am trying to implement a controller which has its scope variable being set by service variable like this :
$scope.sidebar= resourceService.sidebar;
The variable sidebar is set by a function called on startup:
var cb = function (api, data) {
for (var key in data) {
var logoArray = data[key];
service.sidebar[key] = logoArray.map(function (logo) {
logo.img = api + "/" + logo.img;
return logo;
});
}
}
service.requestOnStartup = function (api) {
var defer = $q.defer();
$http.get(config.ApiEndpoint.Base + api).success(function (data) {
if (angular.isObject(data)) {
defer.resolve(cb(api, data));
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
defer.reject(data);
}
}).error(function (msg) {
$log.error("Invalid request");
defer.reject(msg);
});
return defer.promise;
};
While the control reaches the scope, the service variable is still not resolved and by the time it is resolved, the control over scope is lost. How do i tackle this problem using promises ?
Your code looks fine if you are displaying $scope.sidebar directly. The variable will be filled asynchronously so it will come after a moment.
If you are doing some action on it while the controller is loading, you'll need to use $watch
$scope.$watch('sidebar', function() {
if ($scope.sidebar) {...} // check for existence here
});
By the way, you can simplify your requestOnStartup like this
service.requestOnStartup = function (api) {
return $http.get(config.ApiEndpoint.Base + api).then(function (data) {
if (angular.isObject(data)) {
return cb(api, data);
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
return $q.reject(data);
}
}, function (msg) {
$log.error("Invalid request");
return $q.reject(msg);
});
};
You can also use the existing $q service of angular js:
service.requestOnStartup = function (api) {
return $q(function(resolve, reject){
$http.get(config.ApiEndpoint.Base + api).then(function (data) {
if (angular.isObject(data)) {
resolve(cb(api, data));
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
reject(data);
}
}, function (msg) {
$log.error("Invalid request");
reject(msg);
});
});
};

NodeJS http.request not returning data even after specifying return on the 'end' event

Basically I am trying to scrap some data from website and perform the DOM extraction, deletion and updation on a callback function binded to the 'end' event of http.request.
I have returned the data from the 'end' event callback too but it is not receiving in my route callback function. I get undefined there.
Below is the code block:
var scraper = {
extractEmail: function (directoryName) {
var result = getDirectory(directoryName);
if (result !== 404) {
var protocol = result.https ? https : http;
protocol.request({
host: 'somevalue.net',
method: "GET"
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
return data;
});
})
.on('error', function (err) {
return err;
})
.end();
//return data;
}
else {
//return "Failed";
}
}
};
And here is the Routes.js function:
app.get('/:directory', function (req, res) {
var n = scraper.extractEmail(req.params.directory);
console.log(n);
res.send(n);
});
In here also I don't get the value of n.
Is your 'var scraper' also in the route.js file?
I guess it's not and you are unable to access that other js file,
for doing so use module.exports.
eg.
// module.js
var name = "foobar";
// export it
exports.name = name;
Then, in route.js...
> //route.js
> // get a reference to your required module
> var myModule = require('./module');
> //correct path to folder where your above file is
> // name is a member of myModule due to the export above
> var name = myModule.name;
You cannot return a value from an asynchronous callback. Well, you can, but it most likely will get ignored and most certainly won't do what you want.
You cannot even return a promise in that place. You can only resolve a promise where you now use the return statements. You need to return a promise from the main function and then resolve or reject the promise in your event handlers where you use returns now.
For more info see those answers:
Return Promise result instead of Promise in Nodejs
Return value in function from a promise block
jQuery: Return data after ajax call success
The simplest modification that will make this work is to pass a callback function to extractEmail to receive the data once it's ready.
var scraper = {
extractEmail: function (directoryName, cb) {
var result = getDirectory(directoryName);
if (result !== 404) {
var protocol = result.https ? https : http;
protocol.request({
host: 'somevalue.net',
method: "GET"
}, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
cb(null, data);
});
})
.on('error', function (err) {
cb(err);
})
.end();
}
else {
cb(new Error('Failed'));
}
}
};
And use it like this:
app.get('/:directory', function (req, res) {
scraper.extractEmail(req.params.directory, function(err, n) {
if (err) return console.error(err);
console.log(n);
res.send(n);
});
});

How to pass resolved promise to a scope in AngularJS?

So I started using AngularJS and currently looking at promises. So my old code looks like this:
app.controller('CustomerController', function ($scope Customers, $q) {
init();
function init() {
Customers.getCustomers()
.then(function (response) {
$scope.customers = response.data;
}, function (error) {
console.log(error);
});
}
});
app.factory('Customers', function ($http) {
return {
getCustomers: function () {
return $http.get('/api/customers');
}
};
});
So what I did in my init function to make a promise is like this:
function init() {
var deferred = $q.defer();
Customers.getCustomers()
.then(function (response) {
deferred.resolve(response.data); // how to pass this into my scope?
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
As you can see, I'm not able to pass it to my scope. Am I doing something wrong here?
I'm not sure what are you trying to do here. But it doesn't make sense to use promises like this in controller. You would need to call your init function somewhere else like this:
init().then(response => $scope.data = response);
In your old code in factory the get method of $http service is returning a promise and you correctly handle the response in controller.
Take into account that the $http service from Angular, already returns a promise. The $http API is based on the deferred/promise APIs exposed by the $q service.
So you could have something like this:
app.controller('CustomerController', function ($scope, Customers) {
init();
function init() {
Customers.getCustomers()
.then(function (data) {
$scope.customers = data;
}, function (error) {
console.log(error);
});
}
});
app.factory('Customers', function ($http) {
return {
getCustomers: function () {
var promise = $http.get('/api/customers').
then(function(response){
return response.data;
},
function(error) {
return response.error;
}
)
return promise;
}
};
});

Promise does not return the right object

I have a problem with the following chain of promises:
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook
, facebookID: FACEBOOKID
}, {
success: function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
var bool = userdata.isnewuser
alert('bool' + bool)
return bool
}
, error: function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
}
})
.then(function (isnewuser) {
$localStorage.organizerAccess = true;
alert('fbdata' + JSON.stringify(isnewuser))
})
I would like to make the first promise to return the boolean 'isnewuser' to the second promise but instead the whole 'userdata' object is returned. Any idea?
success is a callback function its return value won't pass to the next then. if you want to pass the bool value to next one need to rewrite code like below.
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook
, facebookID: FACEBOOKID
}, {
error: function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
}
}).then(function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
var bool = userdata.isnewuser
alert('bool' + bool)
return bool
})
.then(function (isnewuser) {
$localStorage.organizerAccess = true;
alert('fbdata' + JSON.stringify(isnewuser))
})
as the documentation says - then(successCallback, [errorCallback], [notifyCallback]) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected.
so, instead of taking the returned value then takes the object returned which caused the success: function (userdata) which is userdata
login: function () {
var deferred = $q.defer();
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook,
facebookID: FACEBOOKID
}).error(function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
})
.then(function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
deferred.resolve(userdata.isnewuser);
});
return deferred.promise;
}
write this function in service class and call it from controller

deferred promise value not updating/resolving/deferring

I have a controller function that creates something. When the function is called, a setInterval run to get the status of the item.
Here is the service:
(function () {
'use strict';
function myService($q) {
let deferred = $q.defer();
function createSomething(name) {
Meteor.call('createSomething', name, (err, res) {
if (err) {
deferred.reject(err);
} else {
//value returned is the created item (id, name, status)
deferred.resolve(res);
}
});
return deferred.promise;
}
function getStatus(id) {
Meteor.call('getStatus', id, (err, res) {
if (err) {
deferred.reject(err);
} else {
//statuses are queued, processing, created
deferred.resolve(res);
}
});
return deferred.promise;
}
return {
createSomething: createSomething,
getStatus: getStatus
}
}
angular.module('myApp').factory('myService', myService);
})();
And here is the controller:
(function () {
'use strict';
function myController($scope, myService) {
let ctrl = this;
ctrl.create = (name) => {
myService.createSomething(name)
.then((item) => {
ctrl.statusInterval = setInterval(() => {
myService.getStatus(item.data.id)
.then((status) => {
//status is always 'queued' :(
if (status.data.status === 'created') {
clearInterval(ctrl.statusInterval);
//do something
}
});
}, 5000);
});
};
}
angular.module('myApp').controller('myController', myController);
})();
When I check the value of the response in getStatus of the service, the status changes every time it is called (queue -> processing ... processing -> created). However, the value of status in the controller is always queue.
How do I get the promise value to resolve?
createSomething() and getStatus() need to create and return their own promise. They can't share a promise and work properly in all cases.
In addition, they should create and return a unique promise each time they are called, not the same promise every time they are called. Remember, promises are one-way state machines. Once resolved or rejected, their state never changes, even if resolve() or reject() is called again on them.
Here's an example:
function createSomething(name) {
// create a unique deferred inside this function each time you call it
let deferred = $q.defer();
Meteor.call('createSomething', name, (err, res) {
if (err) {
deferred.reject(err);
} else {
//value returned is the created item (id, name, status)
deferred.resolve(res);
}
});
return deferred.promise;
}

Categories