I have 2 functions bindclub() and displayevent(). I want to assure bindclub() to run first always.I have also tried to put both the functions in ng-init but it also does not assured to run bindclub() first
angular.module('app', []).controller("EventCtrl",EventController);
EventController.$inject = ["$scope", "$http", "$window"];
function EventController($scope, $http, $window) {
$scope.bindclub = function () {
$http({
url: '/Master/bindclub',
method: 'post',
}).then(function (response) {
debugger
$scope.clubidname = response.data;
}, function () { alert("Error in binding club"); });
}
$scope.displayevent = function () {
$http({
url: '/Master/displayevent',
method: 'post',
}).then(function (response) {
alert('Displayed');
}, function () { alert('Error in display event'); });
}
$scope.bindclub ();
$scope.displayevent ();
}
Is the second event dependent on the first event? If yes then you may set it as a callback event of the first event, to ensure that it is triggered on the success of the first event.
use callback function wait until bindclub function executing and then start displayevent function
angular.module('app', []).controller("EventCtrl", EventController);
EventController.$inject = ["$scope", "$http", "$window"];
function EventController($scope, $http, $window) {
$scope.bindclub = function(callback) {
$http({
url: '/Master/bindclub',
method: 'post',
}).then(function(response) {
debugger
$scope.clubidname = response.data;
callback() // callback function
}, function() {
alert("Error in binding club");
callback()// callback function
});
}
$scope.displayevent = function() {
$http({
url: '/Master/displayevent',
method: 'post',
}).then(function(response) {
alert('Displayed');
}, function() {
alert('Error in display event');
});
}
$scope.bindclub(function() {
$scope.displayevent(); // this execute after bindclub fucntion
});
}
The function bindclub is indeed being run before displayevent. But these two functions themselves make http calls which have callbacks. There is no guarantee to have the callbacks executed in the order you want.
The only work around I see is to call the other function inside of the callback in bindclub.
The other way is for you to chain the callbacks.
You can attach displayEvent to a custom event that is triggered inside the bindEvent callback.
Check out this SO post for example on how to do this.
Return the promise and then chain them:
$scope.bindclub = function () {
//vvvv RETURN httpPromise
return $http({
url: '/Master/bindclub',
method: 'post',
}).then(function (response) {
debugger
$scope.clubidname = response.data;
}, function () { alert("Error in binding club"); });
}
//CHAIN them
$scope.bindclub()
.then(function () {
$scope.displayevent();
});
Since the $http service returns a promise, the second operation can be chained from the first operation with the .then method of the first promise.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am trying to resolve a $http get request before I return it but I seem to always get undefined result.
I have spent a lot of time researching and trying different methods out and still cannot seem to solve it, can any of you see where I am going wrong?
This is the services.js file
(function() {
angular.module('Home')
.factory('HomeService', HomeService);
function HomeService($http) {
return {
getStatus: getStatus()
};
function getStatus($scope) {
$http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
}
}
}());
This is the controller where I hope to send the resolved result.
function HomeController(HomeService) {
HomeService.getStatus;
console.log(HomeService.getStatus)
};
This is learning to use promises. Here is a quick way to get what you want. I would look into promises and the $q function which you can also implement but I won't detail here. Angular docs on $q
Basically, you return the promise from the service and implement the code to run when the promise returns inside the controller.
(function() {
angular.module('Home')
.factory('HomeService', HomeService);
function HomeService($http) {
return {
getStatus: getStatus
};
function getStatus($scope) {
return $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
});
}
}
// Your controller should use the service like this
function HomeController(HomeService) {
HomeService.getStatus().then(function(response){
console.log(response.data);
},function(response){
console.log('an error occured');
});
}());
You can return your promise in your service so it can be resolved in your controller:
Service:
function getStatus() {
var promise = $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
});
promise.then(function(data) {
return data.data;
});
};
Controller:
HomeService.getStatus().then(function(status) {
$scope.status = status;
});
try this:
(function() {
angular.module('Home').service('HomeService', HomeService);
function HomeService($http) {
this.getStatus = function() {
return $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
}
}
}());
and in your controller:
angular.module('yourApp')
.controller('yourController', ['HomeService',
function(HomeService){
function getStatusFromSrv(){
var status;
HomeService.getStatus().then(function(response){
status = response;
console.log("status:" , status);
});
}
}
])
I have a service that do two $http.get to get data from two source and concat into an array and return it to controller.
angular.module('starter.controllers').factory('GetDataList', function ($http) {
var arrDataList = [];
var postData1 = {
"param": "1"
};
var postData2 = {
"param": "2"
};
$http({
method: 'GET',
url: 'https://localhost/search',
data: postData1
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
$http({
method: 'GET',
url: 'https://localhost/locate',
data: postData2
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
return {
getAPIData: function () {
debugger
return arrDataList;
}
};
});
In my controller, I call it like this:
$scope.GetList = function () {
debugger
$scope.item = GetDataList.getAPIData();
$scope.$broadcast('scroll.infiniteScrollComplete');
}
When I use the debugger in console, I notice that
1) getAPIData() will be called first but it has data in it
2) Next debugger triggered at the controller which GetDataList.getAPIData(); does not return any data for $scope.Item
3) The last debugger reach $http call which return the data correctly as I observed in the console. But it never reach the controller side afterwards so no data is being displayed in the mobile app
I read about the natural behavior of angular async call so this seems to be normal. But in my case, what should I do to ensure that the data could reach the controller?
Many thanks
To achieve that without loosing performance, you should use $q.all(), so it will keep your request async and it will return the data once all the promises are resolved. Don't try a synchronic approach because that will reduce your performance.
You can use it like this:
Your factory:
app.factory('GetDataList', function($q, $http) {
var promises = [];
var arrDataList = [];
var requests = [{
url: 'https://localhost/search',
postData: {
"param": "1"
}
}, {
url: 'https://localhost/locate',
postData: {
"param": "2"
}
}];
angular.forEach(requests, function(req) {
executeRequest(req);
})
function resolveData(data) {
debugger
if (arrDataList.length === 0) {
arrDataList = data.data;
} else {
arrDataList = arrDataList.concat(data.data);
}
}
function executeRequest(req) {
var promise = $http({
url: req.url,
method: 'GET',
data: req.postData
})
.then(resolveData);
promises.push(promise)
}
return {
getAPIData: function() {
debugger
return $q.all(promises).then(function() {
return arrDataList
});
}
}
});
And your controller:
$scope.GetList = function() {
debugger
GetDataList.getAPIData().then(function(item) {
$scope.item = item
});
$scope.$broadcast('scroll.infiniteScrollComplete');
}
What we are doing here is executing each request inside the requests array (using its url and postData) asynchronously and saving the promises inside an array. When getApiData is called, it returns a function that will be called after $q.all(promises), that means it will return the data after all those promises are finished (the promises ask if the arrDataList is empty and concats the new data if it's not).
This way you get to keep your async calls! And inside the controller you receive a promise instead of the data itself.
You should make it to be synchronized as in the below
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,serviceDemo) {
$scope.name = 'World';
});
app.factory('serviceDemo', function ($http) {
var arrDataList = [];
var postData1 = []; var postData2 =[]
var firstMethod=function(){
$http({
method: 'GET',
url: 'a.json'
})
.then(function (response) {
console.log(response);
postData1=response.data;
arrDataList.push(postData1);
// console.log(postData1);
secondMethod(); //put the second method call here
});
}
var secondMethod=function(){
$http({
method: 'GET',
url: 'b.json'
})
.then(function (response) {
postData2=response.data;
arrDataList.push(postData2);
console.log(arrDataList);
});
}
var getAPIData= function () {
firstMethod();
return arrDataList;
}
return {
getAPIData: getAPIData
};
});
Modification Made:
You need to call the second method inside the success block of your first method. By this way your first method gets executed, when the result is fetched your second method gets executed and then only control will come out of the first method block.
LIVE DEMO
I´m trying to create an angular function inside on Service to return acess data via $http and then return to a desired scope.
So my service it something like this;
app.service('agrService', function ($http) {
this.testinho = function(){
return "teste";
}
this.bannerSlides = function(){
var dataUrl = "data/banner-rotator.json";
// Simple GET request example :
$http({
method: 'GET',
dataType: "json",
url: dataUrl
})
.success( function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
//console.log(data);
return data;
}).error( function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
alert("Niente, Nada, Caput");
});
}
})
Then i want to associate the returned data to a scope inside of my main App controller... like this:
app.controller('AppCtrl', function($scope, $http, agrService) {
$scope.slides = agrService.bannerSlides();
})
Then in my template i want to loop the data like this:
<div ng-repeat="slide in slides">
<div class="box" style="background: url('{{ slide.url }}') no-repeat center;"></div>
</div>
The problem is that the data it´s only available on success and i don´t know how to pass it to my scope slides!!!!!
What i´m doing wrong?
Many thanks in advance
bannerSlides() doesn't return the values you need right away. It returns a promise that you can use to obtain the value at a later time.
In your service you can use the .then() method of the promise that $http() produces to do initial handling of the result:
return $http({
method: 'GET',
dataType: "json",
url: dataUrl
}).then(function (data) {
// inspect/modify the received data and pass it onward
return data.data;
}, function (error) {
// inspect/modify the data and throw a new error or return data
throw error;
});
and then you can do this in your controller:
app.controller('AppCtrl', function($scope, $http, agrService) {
agrService.bannerSlides().then(function (data) {
$scope.slides = data;
});
})
Use this in your service
....
this.bannerSlides = function(){
var dataUrl = "data/banner-rotator.json";
return $http({
method: 'GET',
dataType: "json",
url: dataUrl
});
};
...
And this in your controller
agrService.bannerSlides().then(function(data) {
$scope.slides = data;
}, function() {
//error
});
you don't need $q promise inside the service because the $http is returning a promise by default
The $http service is a function which takes a single argument — a configuration object — that is
used to generate an HTTP request and returns a promise with two $http specific methods: success and error
reference
here is a Fiddle Demo
You need to return a promise and update your scope in the callback:
app.service('agrService', function ($q, $http) {
this.bannerSlides = function(){
var ret = $q.defer();
var dataUrl = "data/banner-rotator.json";
// Simple GET request example :
$http({
method: 'GET',
dataType: "json",
url: dataUrl
})
.success( function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
ret.resolve(data);
}).error( function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
ret.reject("Niente, Nada, Caput");
});
return ret.promise;
}
})
app.controller('AppCtrl', function($scope, $http, agrService) {
$scope.slides = null;
agrService.bannerSlides().then(function(data){
$scope.slides = data;
}, function(error){
// do something else
});
})
You can't return a regular variable from an async call because by the time this success block is excuted the function already finished it's iteration.
You need to return a promise object (as a guide line, and preffered do it from a service).
Following angular's doc for $q and $http you can build yourself a template for async calls handling.
The template should be something like that:
angular.module('mymodule').factory('MyAsyncService', function($q, http) {
var service = {
getData: function() {
var params ={};
var deferObject = $q.defer();
params.nameId = 1;
$http.get('/data', params).success(function(data) {
deferObject.resolve(data)
}).error(function(error) {
deferObject.reject(error)
});
return $q.promise;
}
}
});
angular.module('mymodule').controller('MyGettingNameCtrl', ['$scope', 'MyAsyncService', function ($scope, MyAsyncService) {
$scope.getData= function() {
MyAsyncService.getData().then(function(data) {
//do something with data
}, function(error) {
//Error
})
}
}]);
I have the following script:
$q.all([
getActive(),
getUser()
])
.then(function (results) {
var x = results[0];
var y = results[1];
}
function getActive() {
$http({
url: '/api/Test/GetActive',
method: "GET"
})
};
function getUser() {
$http({
url: '/api/Test/GetUser',
method: "GET"
})
};
I was expecting to see that the variables x and y would contain the results of the $http calls but they both show as undefined.
Can someone suggest how I can make these calls return a promise. I actually thought $http did return a promise so I am confused.
You seem to be missing the return statement in both the getActive() and getUser() functions.
Try this:
$q.all([
getActive(),
getUser()
])
.then(function (results) {
var x = results[0];
var y = results[1];
}
function getActive() {
return $http({
url: '/api/Test/GetActive',
method: "GET"
});
};
function getUser() {
return $http({
url: '/api/Test/GetUser',
method: "GET"
});
};
Here's a working example. I changed your code in a few small ways. Note: The returned promises from the individual calls, the simplified way of calling $http, and pulling the data out of the returned results in the then() function:
http://plnkr.co/edit/YStkRt?p=info
function MainCtrl($scope, $q, $http) {
$q.all([
getActive(),
getUser()
])
.then(function (results) {
$scope.ip = results[0].data;
$scope.headers = results[1].data;
});
function getActive() {
return $http.get('http://ip.jsontest.com/');
}
function getUser() {
return $http.get('http://headers.jsontest.com/');
}
}
I have some code in my controller that was directly calling $http to get data.
Now I would like to move this into a service. Here is what I have so far:
My service:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId, callback) {
$http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
}).success(function (result) {
callback(result);
});
};
return TestAccount;
});
Inside the controller:
TestAccount.get(3, function (data) {
$scope.testAccounts = data;
})
How can I change this so rather than passing the result of success back it
passes back a promise that I can check to see if it succeeded or failed?
Make your service to return a promise and expose it to service clients. Change your service like so:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId) {
return $http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
});
};
return TestAccount;
});
so in a controller you can do:
TestAccount.get(3).then(function(result) {
$scope.testAccounts = result.data;
}, function (result) {
//error callback here...
});