Set a function to await response when calling through another function - javascript

Using JavaScript and AngularJS, I have a controller function looking to set a bool based on the return of a service call, which awaits the return of an API call. How do I write the controller function to wait for the API response?
Controller...
var someBoolValue = false;
function firstCheck() {
// function checks other things
if (someCheck) {
// how do I set someBoolValue to await the response, this code did NOT work
SomeService.CheckforSomething(data, moreData).then(function (response) {
someBoolValue = response;
});
}
Service...
function CheckforSomething(data, moreData) {
var anImportantNumber = null;
var anotherNumber = 456;
// function does other things
anImportantNumber = 123;
if (someCondition) {
ApiService.GetMyData()
.then(function (data) {
anImportantNumber = data.ThisValue.WRT;
}
}
return (anImportantNumber != anotherNumber);
}
API Service...
function GetMyData() {
uri = 12345;
$http.get(uri)
.then(function (response) {
dererred.resolve(response.data)
}
return deferred.promise;
}

Related

Why isn't my variable available inside the scope of an AngularJS promise?

I write promises to take from back-end some data. But function end() don't see my variable witch contains this data. What I'm doing wrong, and how to return overlappingProjects variable?
Console.log(1 and 2) shows massive with data but console.log(4) already have empty object.
this.checkSingleInvitation = function(invitation) {
console.log('Оверлап сингл');
var dtoArray = [];
var overlappingProjects = {};
InvitationService.acceptedProjects.models.forEach(function(accepted) {
if(!(dateHelper.parseDate(accepted.dt_from) > dateHelper.parseDate(invitation.dt_to) || dateHelper.parseDate(accepted.dt_to) < dateHelper.parseDate(invitation.dt_from))) {
var dto = {
target: invitation.project_has_musicians_id,
goal: accepted.project_id
};
dtoArray.push(dto);
}
});
var promises = [];
angular.forEach(dtoArray, (function(dto) {
var deferred = $q.defer();
var overlappingProjects = {};
//async fun
InvitationService.checkOverlapping(dto)
.before(function() {
progressBars.progressbar.requestsInProgress++;
})
.success(function(data) {
// TODO: overlappingProjects - ???
if(Object.keys(data).length) {
console.log('1');
console.log(data);
overlappingProjects = data;
console.log(overlappingProjects);
}
console.log('2');
console.log(data);
deferred.resolve(data);
})
.error(function(error) {
deferred.reject(error);
})
.finally(function() {
progressBars.progressbar.requestsInProgress--;
});
promises.push(deferred.promise);
}));
$q.all(promises).then(console.log(promises)).then(
end()
);
function end() {
console.log('4');
console.log(overlappingProjects);
return overlappingProjects;
}
}
The problem seems to be that you are defining overlappingProjects twice.
Remove the second definition:
angular.forEach(dtoArray, (function(dto) {
var deferred = $q.defer();
var overlappingProjects = {}; // <-- remove this line
In addition to twice variable(overlappingProjects) declaration, you call end function immediately instead of pass it as callback:
$q.all(promises).then(console.log(promises)).then(
end()
);
Should be:
$q.all(promises)
.then(() => console.log(promises)) // may be .then(results => console.log(results)) ?
.then(end);

$watch a service when theres changes

I want to watch changes in my services like in my system logs when there's someone who login the getlogs function must trigger how to achieve this ???
dashboard.controller
function getLogs() {
return dataservice.getLogs().then(function (data) {
vm.logs = data;
return vm.logs;
});
}
dataservice.js
function getLogs() {
return $http.get('/api/timeLogs')
.then(success)
.catch(fail);
function success(response) {
return response.data;
}
function fail(e) {
return exception.catcher('XHR Failed for getPeople')(e);
}
}
I've tried this but its not working
$scope.$watch('dataservice.getLogs()', function () {
getLogs();
}, true);
This is a case for observable pattern where you subscribe for changes on your service
app.service('dataservice', function($http) {
var subscribers = [];
var addSubscriber = function(func){
subscribers.push(func);
}
var notifySubscribers = function(){
for(var i = 0; i< subscribers.length; i++){
subscribers[i](); //invoke the subscriber
}
};
var addLog = function(){
//let's say that the logs are added here
//then notify the subscribers that a new log has been added
notifySubscribers();
};
var getLogs = function() {
return $http.get('/api/timeLogs')
.then(success)
.catch(fail);
function success(response) {
return response.data;
}
function fail(e) {
return exception.catcher('XHR Failed for getPeople')(e);
}
};
return {
addSubscriber: addSubscriber,
addLog: addLog,
getLogs: getLogs
}
});
Then in your controller add a subscriber function to the service
dataservice.addSubscriber(function(){
console.log('new log added');
dataservice.getLogs();
});
NOTE: this can also be done with the RxJs library
if you want to check and get data's change from server, watching a service is not for that, use a polling service.
you check for every 1sec (for example) from a server:
example:
$interval(function() {
dataservice.getLogs().then(function(data) {
vm.logs = data;
});
}, 1000);
or much better:
getLogs = function () {
dataservice.getLogs().then(function(data){
vm.logs = data;
$timeout(getLogs, 1000)
});
}

Can't execute 2 $http calls in angularjs at the same time

I am implementing long polling to know the state of some long running event on the server side. I create my own factory that will notify me when a server event triggers. Here is the factory.
.factory("$httpPolling", function ($http) {
function $httpPolling($httpService) {
var _responseListener, _finishListener;
var cancelCall = false;
var _pollId;
function waitForServerCall(id) {
console.log("executing waitForServerCall");
$httpService.get(href("~/polling/" + id))
.success(function (response) {
var cancelPolling = _responseListener(response);
if (cancelPolling || cancelCall) {
return;
}
else {
waitForServerCall(id);
}
});
};
function _sendData(httpMethod, url) {
var pollingId = guid();
_pollId = pollingId;
if (url.split("?").length == 2) {
url += "&pollid=" + pollingId;
}
else {
url += "?pollid=" + pollingId;
}
if (httpMethod == 0) {
$httpService.get(url).success(function (response) {
if (_finishListener) {
_finishListener(response);
}
cancelCall = true;
});
}
else {
$httpService.post(url).success(function (response) {
if (_finishListener) {
_finishListener(response);
}
cancelCall = true;
});
}
}
var $self = this;
this.get = function (url) {
_sendData(0,url);
return $self;
};
this.post = function (url) {
_sendData(1, url);
return $self;
};
this.listen = function (_listener) {
_responseListener = _listener;
waitForServerCall(_pollId);
return $self;
}
this.finish = function (_finish) {
_finishListener = _finish;
return $self;
}
}
return new $httpPolling($http);
});
Where the sintax of usage should be:
$httpPolling.get("url")
.listen(function(event){
// fires when server event happend
})
.finish(function(response){
// fires when the long running process finish
});
The problem is that _sendData method does not execute asynchronously because the waitForServerCall only executes the ajax call when the _sendData(long running process) method get the response from the server.
Why? Is this an angular behavior?
Angular $httpProvider has an option provided for async http calls, which is set to false as default value.
Try
app.config(function ($httpProvider) {
$httpProvider.useApplyAsync(true);
});

Angular promises: get data from buffer if available

In this scenario the requirement is to get the data with an Http request if the data is not in a buffer. If it's in the buffer, use it from there without the Http request.
I tried the code below but it doesn't make much sense; if the data is in the buffer I don't know if I should return from the function doing nothing or return the deferred promise. Any thoughts?
var dataBuffer = null;
var getData = function() {
var deferred = $q.defer();
if (dataBuffer != null) { // this is the part I'm not convinced
deferred.resolve();
return;
}
$http.get('/some/url/')
.success(function(data) {
dataBuffer = data;
deferred.resolve();
})
.error(function(data) {
deferred.reject();
});
return deferred.promise;
};
Invoked in the following way:
var promise = getData();
promise.then (
function(response) {
dataBuffer = .... // dataBuffer contains data
}
);
There is a clean simple way to use promises when you're not sure which is the code you're executing is asynchronous or not and it's using $q.when
So the code can be:
var getData = function() {
return $q.when(dataBuffer ? dataBuffer: $http.get('/some/url'))
};
Then when calling getData you can use the same code you posted or just simply:
getData()
.then(function(response){//...
})
.catch(function(err){//..
});
Beware of the deferred antipattern. You can accomplish what you are trying to do very cleanly, like this:
var dataBuffer;
var getData = function() {
if (dataBuffer) {
// return a resolved promise for dataBuffer if it is already populated
return $q.when(dataBuffer);
}
$http.get('/some/url/')
.then(function (data) {
dataBuffer = data.data;
return dataBuffer;
});
};
getData().then(function (data) {
// data contains the data you want
})
.catch(function (error) {
// error occurred.
});
dataBuffer should not be accessed outside of your getData function. To make this perfectly clear, you can wrap them together in an IIFE, although this is optional:
var getData = (function () {
var dataBuffer;
return function() {
if (dataBuffer) {
// return a resolved promise for dataBuffer if it is already populated
return $q.when(dataBuffer);
}
$http.get('/some/url/')
.then(function (data) {
dataBuffer = data.data;
return dataBuffer;
});
};
})();
getData().then(..etc etc etc...);
As a final note, remember that you can use $http's built-in caching features, and not have to reinvent the wheel with your own buffers:
// much simpler, isn't it?
var getData = function() {
$http.get('/some/url/', { cache: true }) // enable caching
.then(function (data) { return data.data });
};
getData().then(...etc etc etc...);
Why dont you enable cache instead of handling the buffer manually.
$http.get('/some/url/',{ cache: true})
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
deferred.reject();
});

Angularjs $resource get/post returning same result

I'm brand new to angular, so I'm probably doing things all wrong. My query is returning an array of objects like it should be. I then do a click event to test the post..it hits my web api just fine...but then it returns that same array from my get. I'm guessing this is cached? Why would my post show the results of my earlier get?
Edit - Sorry, I could have been more clear. When I run my saveTest method, a post fires and my array saves, however the 'result' variable of that save..is the array from my original get.
app.directive('referenceSection', function () {
return {
restrict: 'E',
templateUrl: '/app/loanapplication/views/reference-section.html',
controller: function ($scope, referenceService) {
$scope.json = angular.toJson($scope.referenceArray);
$scope.referenceArray = [];
referenceService.query().$promise.then(function (result) {
$scope.referenceArray = result;
}, function () {
alert("fail");
});
$scope.saveTest = function () {
referenceService.save(angular.toJson($scope.referenceArray)).$promise.then(function (result) {
var x = result;
}, function () {
alert("save fail");
});
}
}
};
});
Service
app.factory('referenceService', function ($resource) {
var requestUri = '/api/reference';
return $resource(requestUri)
});
Web api
public class ReferenceController : BaseController
{
public HttpResponseMessage Get()
{
List<WebReference> references = new List<WebReference>();
WebReference reference = new WebReference();
WebReference reference2 = new WebReference();
reference.Name = "Andrew";
reference.Relationship = "QuickSupport";
reference.Id = 1;
reference2.Name = "Josh";
reference2.Relationship = "Hansen";
reference2.Id = 2;
references.Add(reference);
references.Add(reference2);
if (references == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Request.CreateResponse<IEnumerable<WebReference>>(HttpStatusCode.OK, references);
}
public HttpResponseMessage Post([FromBody]WebReference[] references)
{
try
{
var msg = new HttpResponseMessage(HttpStatusCode.Created);
return msg;
}
catch (Exception e)
{
throw new HttpResponseException(HttpStatusCode.Conflict);
}
}
}
}
referenceService.query().$promise.then(function (result) {
$scope.referenceArray = result;
After this, you need to call $scope.$apply() to inform angular of your changes made to be bound. If I guessed your question correctly .
:-)
From where you are reading response? From x that is not available outside then function or it is mistake to not attach it to referenceArray
referenceService.save(angular.toJson($scope.referenceArray)).$promise
.then(function (result) {
var x = result;
}, function () {
alert("save fail");
});

Categories

Resources