I need resolve the http call in my service to return the data, not a promise.
Is this possible with AngularJS (with Ionic Framework)?
Service code:
.factory('ClientService', function ($http) {
const url = 'http://myAPIurl';
var self = this;
var result = [];
self.getClients = function () {
return $http.get(url).then(function (response) {
return response.data;
});
}
return self;
})
In my controller, I use this code that actually returns a promise of my request. In this point, the $scope.clients must be filled with data.
Controller code:
ClientService.getClients().then(function (response) {
$scope.clients = response;
}, function (e) {
console.log(e);
});
Related
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;
}
};
});
Here I have make the Http Request and get the response from first Service call and pass the response of first service inside the second service and get the response and to controller.
I got the response , how i could get into controller.
app.factory('logHomeService', function () {
var getHomeService = function (LoginService, HomeService) {
return
{
LoginService.After("user", encodeURIComponent("pass"))
.then(function (response) {
debugger;
$stateParams.User = "admin";
var mydata = response.CT1SessionObj;
var DefaultModelObj = { cobj: mydata};
HomeService.pageLoad(DefaultModelObj)
.then(function (response) {
$rootScope.CT1SessionObj = response.mydata;
}, function (response) {
console.log("LoginService" + response.data);
alert(response.Message);
});
},
function (response) {
console.log("Home Service" + response.data);
return response.data;
});
return response.data;
};
};
return {
getHomeService: getHomeService
}
});
app.Controller('HomeController',function($scope,logHomeService)
{
this.logHomeService = logHomeService;
}
here this.logHomeService = logHomeService return the method in factory ,how i get the response result from second service
I need to return home service response to controller, console.log("Home Service" + response.data);
You need to use promises and then listen for the resolution in your contoller.
app.factory('logHomeService', function($q) {
var getHomeService = function(LoginService, HomeService) {
// create a promise object
var deferred = $q.defer();
LoginService.After("user", encodeURIComponent("pass")).then(
function(response) {
$stateParams.User = "admin";
var mydata = response.CT1SessionObj;
var DefaultModelObj = {
cobj: mydata
};
HomeService.pageLoad(DefaultModelObj).then(
function(response) {
$rootScope.CT1SessionObj = response.mydata;
// resolve the promise
deferred.resolve( response );
},
function(response) {
console.log("LoginService" + response.data);
// reject the promise if there is an error
deferred.reject( response );
alert(response.Message);
});
},
function(response) {
console.log("Home Service" + response.data);
// reject the promise if there is an error
deferred.reject( response )
});
// return the promise
return deferred.promise
};
return {
getHomeService: getHomeService
}
});
First inject $q into the Factory. Then return the promise from the the getHomeService() method.
The promise is resolved in 3 locations, 2 rejections and 1 resolve. The rejections can be used to do something in the controller when the call fails.
Next update your controller to listen to the promise.
app.Controller('HomeController', function($scope, logHomeService){
this.logHomeService = logHomeService;
this.logHomeService.getHomeService().then(
function(successResponse){
// success
},
function(failureResponse){
// failure
}
)
}
#Thanks grant you make my day. In Factory have used two service , in the service i have used promises, but i am not used in factory.
var service1 = function ($http, $q, configAPI) {
var crContractApi_Url = configAPI.crContractApi_Url;
this.pageLoad = function (params) {
var result = $q.defer();
params.obj.data = null;
$http({
method: 'POST',
url: baseurl + '/reatiler/retailer',
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(params)
})
.success(function (response) {
result.resolve(response);
})
.error(function (response) {
result.reject(response);
});
return result.promise;
}
like that used in service2. Is thera anyother way
Am using the cordova-file-transfer plugin for uploads in my app, am trying to wrap in the plugin in an ionic factory to make my code more modular.
angular.module('starter.services')
.factory('$uploader', function($q, $cordovaFileTransfer, $user) {
this.uploadLogo = function(filepath, vendorId) {
var q = $q.defer();
var server = encodeURI(logoUploadUrl(vendorId));
$cordovaFileTransfer.upload(server, filepath, this.logoUploadOptions, true)
.then(function (result) {
q.resolve(result);
}, function (error) {
q.reject(error);
}, function (progress) {
q.resolve(progress);
});
return q.promise;
};
return this;
});
When i use the factory in a controller the first "q.resolve" call is not fired, rather the second one is. I just learned how to use JS promises, and i figure i could be doing something wrong. Any help will be appreciated.
Thank you #maurycy for the help. I sorted it out
angular.module('starter.services')
.factory('$uploader', function($q, $cordovaFileTransfer, $user) {
this.uploadLogo = function(filepath, vendorId) {
var q = $q.defer();
var server = encodeURI(logoUploadUrl(vendorId));
$cordovaFileTransfer.upload(server, filepath, this.logoUploadOptions, true)
.then(function (result) {
q.resolve(result);
}, function (error) {
q.reject(error);
}, function (progress) {
q.notify(progress);
});
return q.promise;
};
return this;
});
I have an Angular app with a service (EqService), for which I want to know the Timestamp Marker in the asynchronous call.
I'm using request and response interceptors. The key components are like so:
// app.js
var appModule = angular.module('myApp', []);
appModule.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('timestampMarker');
}]);
appModule.controller('PostsAjaxController', function ($scope, EqService) {
$scope.getData = function (){
EqService.get().then(function (resp) {
console.log(resp);
// Want here 'config.responseTimestamp' and 'config.requestTimestamp';
});
};
$scope.getData();
});
// interceptor.js
appModule.factory('timestampMarker', [function() {
var timestampMarker = {
request: function(config) {
config.requestTimestamp = new Date().getTime();
return config;
},
response: function(response) {
response.config.responseTimestamp = new Date().getTime();
return response;
}
};
return timestampMarker;
}]);
// services.js
appModule.factory('EqService', function ($http, $q) {
return {
get: function () {
var deferred = $q.defer();
$http({ method: 'POST', url: './data.php'}).success(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
});
My question is: How can I have the 'config.responseTimestamp' and 'config.requestTimestamp' after the EqService get call?
You should use then instead of success for consistant promisses. looking at the success implementation
promise.success = function(fn) {
// ...
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
we see that the response gets broken up. To use then your services.js will look like this:
appModule.factory('EqService', function ($http, $q) {
return {
get: function () {
var deferred = $q.defer();
$http({ method: 'POST', url: './data.php'}).then(function (response) {
deferred.resolve(response);
});
return deferred.promise;
}
}
});
Use the config property that comes in the response object. It contains the configuration used to make the request.
Check https://docs.angularjs.org/api/ng/service/$http.
I got a service in Angular:
App.factory('AuthService', function ($q, $http, CredentialStorage) {
var _endpoint = 'http://localhost:3000';
return {
login: function (credentials) {
return $http
.post('/api/users/login', credentials)
.success(function (apiResult) {
var deferred = $q.defer();
if (apiResult.code == 0) {
$scope.user = apiResult.context;
CredentialStorage.store(apiResult.context);
}
return deferred.promise;
})
.fail(function(apiResult, status, headers) {
var deferred = $q.defer();
return deferred.promise;
});
},
....});
Where I authenticate and store the user in some cookie or whatever (this is not relevant).
Then on my controller I got:
App.controller('LoginController', function ($scope, $rootScope, AuthService) {
var _login = function($event) {
$event.preventDefault();
AuthService.login($scope.l).then(function() {
alert('aaa');
if (!AuthService.authenticatedUser) {
$scope.errors = ['Invalid username and password. Please try again.'];
alert($scope.errors);
} else {
alert('a' + $scope.errors);
}
})
}
$scope.login = _login;
});
For some reason my controller's then doesnt execute. Why is that?
Thanks
Well, the simple answer is: you use .then which chains instead of success which just adds a listener:
App.factory('AuthService', function ($q, $http, CredentialStorage) {
var _endpoint = 'http://localhost:3000';
return {
login: function (credentials) {
return $http
.post('/api/users/login', credentials)
.then(function (response) {
var apiResult = response.data;
if (apiResult.code == 0) {
CredentialStorage.store(apiResult.context);
return apiResult.context; // promises let you return the value
}
throw new Error("Authentication failed"); // return $q.reject
// if you don't want to invoke
// exceptionHandler
});
},
....});
Which would let you do:
AuthService.login($scope.l).then(function(result) {
$scope.user = result;
}).catch(function(err){
// code to handle the case authorization failed or the API call failed
});
From Angular separation of concern's stand point, it is generally bad to modify UI scopes in a service/factory/provider. It's better to return the results.