I'm a bit confused by mixing promises and callbacks
I'm trying to do something like this in a factory
startRecord: function (data) {
return $q(function(resolve, reject) {
myFunction(data,resolve,reject);
})
}
which calls
function myFunction(data,callback,error){
...do stuff
if(worked)
callback(response)
else
error(err)
}
And then call it from within my controller like
factory.startRecord(data).then(function(data)...).catch(function(error)...);
However the then or catch are never called..
Am I going the right way about this?
My problem was the callback was being fired with an empty message before the full message was sent. I had to add some extra checks to stop the callback being fired until the message was ready.
Angular $http call it self return promise, you just need to call it perfectly.
Sample code :
Factory:
angular.module(ApplicationName).factory('calendarFactory', ['$http', function ($http) {
calendarFactory.testCall = function (request_params) {
var req = {
method: 'POST/GET',
url: <URL>,
headers: {
'Content-Type': 'application/json'
},
data: request_params
};
return $http(req);
}
}
Controller :
function testCall(start, end) {
var request_paramas = {
start: start.toString(),
end: end.toString()
};
calendarFactory.testCall(request_paramas).then(
function(success){
//Success method
},function(error){
//Error method
})
}
Here I made a back-end http call from factory itself
Related
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.
I have an angular factory doing some $http communication to the server and returning a string. However I get the Cannot read property 'then' of undefined error. I read here and here with similar problems however I was not able to resolve my problem.
This is the service code:
factory("availabilityService", ['$http', function ($http) {
return {
checkAvailability1: function (element, string) {
// ..... some object creation code ......
$http({
method: 'POST',
url: 'server/server.php',
data: AvailableObj,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function successCallback(response) {
return response;
}, function errorCallback(response) {
});
}
}
}]);
Inside a controller:
$scope.checkAvailability = function (element, string) {
availabilityService.checkAvailability1(element, string).then(function (response) { //on this line the error occurs
console.log(response);
});
You need to return the promise returned by $http i.e add a 'return' in front of $http to get your code working like below :
return $http(...)
.then(function successCallback(response) {
return response;
}, function errorCallback(response) {
});
This is because, the function you have called from the controller should have a .then method on it i.e it should be a promise. checkAvailability1 in angular returns a promise which needs to be returned back by your function $http in the factory. You are just returning the response from the success callback which is not expected by your method in the controller.
I'm a little new to Angular, and I'm trying to set up a very simple RPC implementation that uses angulars $http service (factory) to do the work. Here's what I have for the service so far:
'use strict';
angular.module('xxx')
.factory('rpcService', function ($http) {
return {
request: function(method, params, callback) {
var service = method.split('.');
params = params || {};
params.method = service[1];
return $http.post('/services/' + service[0] + '.sjs', params).then(function (response) {
return response.data;
});
}
}
});
Then when I want to use the service, I call it like the following:
rpcService.request('Users.facebookLogin', { token: response.authResponse.accessToken })
.then(function(response) {
debugger;
$rootScope.user = response.user;
console.log($rootScope.user);
$rootScope.loggedIn = true;
$rootScope.$apply();
});
The code never gets to the lines after debugger; In fact, the code never makes the $http request at all. For some reason it stops and doesn't continue with the callback...or promise...I'm a bit confused as to what the technical difference is. :)
That being said, I've tested the POST call with $.ajax and everything returns properly, so something is off with my Angular code.
And the code that actually fires the request and does work with $.ajax:
'use strict';
angular.module('xxx')
.factory('rpcService', function ($http) {
return {
request: function (method, params, callback) {
var service = method.split('.');
params = params || {};
params.method = service[1];
$.ajax('/services/' + service[0] + '.sjs', {
type: 'POST',
dataType: 'json',
data: params,
success: function(data, status, xhr) {
if (callback) {
callback(data);
}
}
});
}
}
});
I'm just unsure why the XHR request isn't being made.
The API call may get an error so the callback was never triggered. Try to add error() callback like this:
return $http("POST", '/services/' + service[0] + '.sjs', params)
.error(function (response) {
return 'blah';
}).then(function (response) {
return response.data;
});
You can try it on this demo. Your code actually looks good.
Demo on jsFiddle
I'm totally new to AngularJs and I have this problem I do not understand. I have two methods. The first one takes some data from a webservice and puts in in a variable defined in the scope. But when I want to use that variable in the second method it is undefined. Can someone help me understand why this is happening and provide a solution?
var myApp= angular.module( "myApp", [] );
myApp.controller("myAppController",
function( $scope ) {
$scope.getAll = function(){
$.ajax({
type: "GET",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
url: ..something...,
success: function (parameters) {
$scope.profiles = angular.copy(parameters); <-- correct data is returned
$scope.$apply();
},
error: function () {
alert("Error calling the web service.");
}
});
}
$scope.getCategories = function(){
var all = $scope.profiles; <-- At this point profiles is empty
...
}
$scope.getAll();
$scope.getCategories();
}
Use the $http service and promises:
$scope.profiles = $http.jsonp(url).then(function(r){ return r.data; });
$scope.categories = $scope.profiles.then(function(profiles) {
var params = { }; // build url params
return $http.jsonp(url, { params: params }).then(function(r){ return r.data; });
});
When you call getCategories(), getAll() hasn't finished yet, which is why profiles is empty. There are several ways to solve this. The best way would be to use promises the built-in $http service.
If you prefer to use jQuery, you can add a watcher on the profiles variable and only when it's populated run the getCategories().
Something like this should work:
$scope.getAll = function(){
$.ajax({
type: "GET",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
url: ..something...,
success: function (parameters) {
$scope.profiles = angular.copy(parameters); <-- correct data is returned
$scope.$apply();
},
error: function () {
alert("Error calling the web service.");
}
});
}
$scope.getCategories = function(){
var all = $scope.profiles;
}
// Wait for the profiles to be loaded
$scope.watch('profiles', function() {
$scope.getCategories();
}
$scope.getAll();
There is no guarantee that getAll has completed before getCategories is invoked, since it is an asynchronous request. So if you want to sequentially invoke getAll and getCategories, you should invoke getCategories inside the success callback of getAll. You could also look into promises for a neater way of chaining asynchronous callbacks (I assume you're using jQuery since you're calling $.ajax).
...
<snipped some code>
success: function(parameters) {
// snipped more code
$scope.getCategories();
}
(and if you're using jQuery promises)
$.ajax(ajaxCallOneOpts).then($.ajax(ajaxCallTwoOpts));
Neither are very "Angularish" though, so you might want to look into some of the provided services for working with http/rest resources instead of using jQuery.
Why are you using a jQuery ajax request in angular? If you write jQuery style code and wrap it angular, you're going to have a bad time...
Here is an angularised version:
myApp.controller("myAppController",
function( $scope, $q, $http ) {
$scope.getAll = function(){
var deferred = $q.defer();
$scope.profiles = deferred.promise;
$http.jsonp('your url').then(function(data) {
deferred.resolve(data);
});
});
$scope.getCategories = function(){
$q.when($scope.profiles).then(function(profiles) {
... <-- At this point profiles is populated
});
}
$scope.getAll();
$scope.getCategories();
}
I am new to angularjs so I am struggling to pass a parameter to service method from controller.
My controller looks like this:
userControllers.controller('StartController', function(startService,$scope) {
var server='http://localhost:8080/terminal/1';
// Call the async method and then do stuff with what is returned inside our own then function
startService.async().then(function(d) {
$scope.message = d;
});
});
Service method:
myService.factory('startService', function($http) {
var startService = {
async: function () {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('http://localhost:8080/terminal/1').then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response.headers('link'));
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
}
};
return startService;
});
And this code works fine. Now I want to pass variable 'server' from controller to be used in service instead of link. Any idea how to do that? How to use more than one variable in service function call?
Updated code is in between ** **
userControllers.controller('StartController', function(startService,$scope) {
var server='http://localhost:8080/terminal/1';
// Call the async method and then do stuff with what is returned inside our own then function
**startService.async(server).then(function(d) {**
$scope.message = d;
});
});
myService.factory('startService', function($http) {
var startService = {
async: **function (server) {**
// $http returns a promise, which has a then function, which also returns a promise
var promise = **$http.get(server)**.then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response.headers('link'));
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
}
};
return startService;
});