Page freeze and $resource - angularjs

So when my page loads, angular calls a service to populate three arrays. This service uses $resource to fetch data (JSON) from the backend. The problem is, while the data is loading the whole page freezes for a second and the spinners are static. My understanding is that $resource and $http are all asynchronous and the page shouldn't freeze when they're active. I've tried the promise pattern approach suggested by this article but without luck. Any advice?
Thanks in advance!
Edit: added the code
mobiModule.factory('DataSrv', function($q, $http) {
return {
getData: function(url) {
var defered = $q.defer();
//make the call
$http.get(url).success(function(data){
console.dir(data);
defered.resolve(data);
}).error(function(){
console.log('HTTP error');
defered.reject();
});
return defered.promise;
}
}
});
$scope.phones = Phones.query(); //using $resource('phones.json')
or
$scope.phones = DataSrv.getData('phones.json'); //using the service defined above

Related

Ensuring all Api's has been loaded in a page in AngularJS

I have 4 controllers in a page in AngularJS. Each controller calls Api's via http request(scope $http). I want to ensure that all the Api's has been called and loaded till then I can show the loading gif image. How to check all the Api's has been loaded in the page in AngulaJS.
I am not sharing the exact code some variable and name I have modified.
myApp.controller('testController',function ($scope, $http, $q, $filter) {
var _promises = {};
_promises['abc'] =
$http({
url: API_URL+'abc-type/',
method: 'GET',
params: {'test1': 'test2'}
});
_promises['abc1'] =
$http({
url: API_URL+'abc-type2/',
method: 'GET'
});
}
$q.all(_promises).then(function (res) {
alert("All promises executed.");
});
});
$http uses promises ($q) for it's API. You can use the $q.all method to run a callback when an array of $http requests are resolved (you will need to make sure all service requests return promises to avoid undefined behavior).
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
It would look something like this
$scope.showLoadingGif = true;
$q.all([MyService.makeGet(), MyService.makeAnotherGet(), ...]).then(function(responses) {
// all the calls have returned a response by this point
$scope.showLoadingGif = false;
})

Error: $injector:undef Undefined Value in angularjs

The response of ajax is like ["99636941","74167247"]. But the values are not accepted by angularjs. The response is ok. If I declare the same response as static, then it is working properly.
app.factory("States", function(){
var states;
$.ajax({
url:'php/usersList.php',
type:'post',
success:function(data,status)
{
states = data;
console.log(states);
},
error:function(xhr,desc,err)
{
console.log(xhr);
console.log("Details: "+ desc + "\n error:"+err);
}
});
return states;
});
Couple of things to note:
Do not use jQuery ajax $.ajax in angularjs service - use $http instead as it will handle digest cycle by itself. Read: https://docs.angularjs.org/api/ng/service/$http
As you are making an ajax call, return states will get executed even before your ajax success event - try looking into Promises in javascript/angular js.
You may refactor this method like:
app.factory("States", function($http){
var getStates function(){
return $http.post('php/usersList.php');//ideally this should be a GET method
};
return {
getStates: getStates
}
});
And in theplace where you call this method:
var states;
States.getStates().then(function(data){
states = data;
})
If we make it more simpler, You can do it the following way.
app.factory("States", function($http){
var factory={};
factory.getStates=function($http){
return $http({
method:'GET',
url:'your URL'
});
};
/*similarly write as many functions as you need and then simply return the factory var*/
return factory;
});

How to make two https calls in single controller on page load Angular JS

I am new to Angular JS
I am trying to make two API calls on page load but I want to do one after another once I got the response I want to call another Asynchronous calls. my service looks as below
can you please suggest me what should be the best way to achieve this.
(function(){
"use strict";
var APIservice = function($http,$base64,UtilService,$rootScope){
UtilService.setHeaders($rootScope.globals.currentUser.authdata);
var DataProvider = function(method,url,data){
return $http({
method: method,
url: url,
data:data
}).then(function(response){
console.log(response);
return response.data;
});
};
return {
DataProvider:DataProvider
}
}
var module = angular.module('expframework');
module.factory("APIservice",APIservice);
}());
Thanks in Advance
Just use promise chaining:
APIservice.DataProvider('GET', firstUrl).then(function(data1) {
return APIservice.DataProvider('GET', secondUrl);
}).then(function(data2) {
// ...
});

How to use ngResource when server is on a different localhost?

I am building an app with Ionic and MEAN stack. My express server is running on localhost:3000 while my Ionic public code is running on localhost:8100. From my research, it seems like Ionic can run on a different IP address from the server and should just use ngResource to send $http requests.
So I have a RESTful endpoint like this in server.js
router.get('/', function(req, res){
res.json({"name":"Abdul"});
});
And on the Ionic client code I am sending in a request like this:
app.controller('mainCtrl', function($scope, $resource){
$scope.test = $resource('localhost:3000/');
$scope.test_button = function(){
console.log($scope.test);
}
});
But when I click the test_button, instead of [{"name":"Abdul"}] being logged in the console, I get the following null message:
function Resource(value) {
shallowClearAndCopy(value || {}, this);
}
Can anyone help me out on connecting the client and server?
$resource object will only create an object with having get, save, update, etc. So for calling get method of server, you need to call get method of $resource object. That method will return $promise object will provide a promise. On which you can place .then promise, in which you will get data in success function.
One more thing is, when you are returning data from the server, you are returning object in array format. So in that case you need to specify get method will return array by having isArray: true option there.
$scope.test = $resource('http://localhost:3000/', {}, {get: { isArray: true}});
$scope.test.get().$promise.then(function(data){ //success function
$scope.test = data;
},function(error){ //error function
console.log(error);
})
to make your application more better, you could move up your $resource object to service/factory to make that call reusable.
app.service('dataService', function($resource){
var resourceUrl = $resource('http://localhost:3000/', {}, {get: { isArray: true} });
this.getData = function(){
return resourceUrl.get().$promise;
};
})
Controller
app.controller('mainCtrl', function($scope, dataService){
$scope.test_button = function(){
dataService.getData().then(function(data){ //success function
$scope.test = data;
},function(error){ //error function
console.log(error);
})
}
});

Delay an angular.js $http service

I have some angular factories for making ajax calls towards legacy ASP.NET .asmx web services like so:
module.factory('productService', ["$http",
function ($http) {
return {
getSpecialProducts: function (data) {
return $http.post('/ajax/Products.asmx/GetSpecialProducs', data);
}
}
} ]);
I'm testing on a local network so response times are "too" good. Is there a smart way of delaying the $http a couple of seconds from making the call to simulate a bad connection?
Or do I need to wrap all calls to the factory methods in a $timeout ?
$timeout(function() {
productService.getSpecialProducs(data).success(success).error(error);
}, $scope.MOCK_ajaxDelay);
Interesting question!
As you mentioned yourself, $timeout is the most logical choice for a delayed call. Instead of having $timeout calls everywhere, you could push a response interceptor that wraps the $http promise in a $timeout promise, as conceptually outlined in the documentation of $http, and register it in one of your configuration blocks. This means all $http calls are affected by the $timeout delay. Something along the lines of:
$httpProvider.interceptors.push(function($timeout) {
return {
"response": function (response) {
return $timeout(function() {
return response;
}, 2500);
}
};
});
As a bonus to your "to simulate a bad connection?", you could reject or do absolutely nothing randomly, too. Heh heh heh.
The new chrome device emulator has a network throttling function:
To get there: In Google Chrome, press F12 to open the Developer Tools. Then, on the top left corner, click the "Toggle device mode" icon (left to the "Elements" menu).
Developing more on the answer of #stevuu
responseInterceptors seems to be depreceted (as of 1.2.20) I have modified the code to work on the interceptors mechanism:
$httpProvider.interceptors.push(function($q, $timeout) {
return {
'response': function(response) {
var defer = $q.defer();
$timeout(function() {
defer.resolve(response);
}, 2300);
return defer.promise;
}
};
});
You could use the $q service for defer().promise pattern:
function someFunction(MOCK_ajaxDelay) {
var deferred = $q.defer();
$http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(function(response) {
$timeout(function() {deferred.resolve({ success: true, response: response })}, MOCK_ajaxDelay);
}).error(function() {
$timeout(function() {deferred.resolve({ success: true, response: response } }, MOCK_ajaxDelay);
});
return deferred.promise;
}
someService.someFunction(500).then(function(data) {
if (data.success) {
$scope.items = data.response.d;
}
});
But if you are really mock testing, the better solution is to look into ngMock: http://docs.angularjs.org/api/ngMock.$httpBackend
While #stevuu's answer is correct, the syntax has changed in the newer AngularJS versions since then. The updated syntax is:
$httpProvider.interceptors.push(["$q", "$timeout", function ($q, $timeout) {
function slower(response) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(response);
}, 2000);
return deferred.promise;
}
return {
'response': slower
};
}]);
You can achieve this using the promise api combined with a $timeout. The $http.post function returns a promise from which you can call .success and .error (these are http specific methods). This promise is resolved when the http request is complete. If you build your own promise then you can tell it to delay 2 seconds and then resolve when the http request is complete:
module.factory('productService', function ($http, $q, $timeout) {
return {
getSpecialProducts: function (data) {
var defer = $q.defer();
$http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(
function(data) {
// successful http request, resolve after two seconds
$timeout(function() {
defer.resolve(data);
}, 2000)
}).error(function() {
defer.reject("Http Error");
})
return defer.promise;
}
}
});
But note - you will have to use promise.then(successCallback, errorCallback) functionality - that is, you'll lose the ability to access http headers, status & config from your controllers/directives unless you explicitly supply them to the object passed to defer.resolve({})
Links:
Defer/Promise Api
Http/Promise Api
Resolve egghead video
In response to the testing aspect of your question, Fiddler has a really useful function that helps when you need to simulate delays:
Click on the AutoResponders tab in Fiddler.
Add a rule with a regex that matches the URL of the request you want to delay.
Set the "respond with" to "*delay:1000" where the number is the delay in milliseconds.
The AutoResponder functionality in Fiddler is extremely useful for testing JS that involves a lot of http requests. You can set it to respond with particular http error codes, block responses, etc.
If you are using a service that returns a promise, then inside you should put a return before the $timeout as well because that returns just another promise.
return dataService.loadSavedItem({
save_id: item.save_id,
context: item.context
}).then(function (data) {
// timeout returns a promise
return $timeout(function () {
return data;
},2000);
});
Hope it helps someone!

Resources