Add Delay in angularjs - angularjs

I want to add some delay in angularjs. So that it can fetch data from api. Because my api is heavy. I am calling this function. Basically i want some delay to load page so that my api work properly. I tried some time my data pull immediate some time i am getting error. When i refresh my page it work fine.
Help to put $timeout function in this angularjs
// Geting test stuff
$scope.teststuff = function () {
$scope.loading = true;
$http.get(settings.WebApiBaseUrl + 'Api/testing')
.success(function (data) {
$scope.mydata = data;
$scope.loading = false;
}).error(function (data, status, headers, config) {
alert("Error " + status )
$scope.loading = false;
})
}

Updated:
This problem can easily be solved by using resolve property of $routerProvider. Please use this config. So here the route /ed will not load until the resolve is completed, meaning the http request must return a value, only after that the page will load.
app.config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) {
var settings.WebApiBaseUrl = "some url you want to use";
$routeProvider.when("/al", { templateUrl: "Views/test.html", controller: "testCtrl" })
.when("/ed", {
templateUrl: "Views/test2.html",
controller: "test2Ctrl",
resolve: {
initialize: function($http, $sessionStorage){
$http.get('api/ApiKey/' + $sessionStorage.user)
.success(function (myKey) {
return $http.get(settings.WebApiBaseUrl + 'Api/test1', { headers: { 'X-ApiKey': myKey } })
.success(function (data) {
return data;
}).error(function (data, status, headers, config) {
alert("error" + status);
});
}).error(function (data, status, headers, config) {
alert("error" + status);
});
}
}
})
.otherwise({
redirectTo: '/al'
});
}]);
Now in the controller you need to do.
app.controller( 'test2Ctrl', function ( $scope, initialize ) {
$scope.loading=false;
$scope.test1=initialize;
$scope.loading=true;
});
Old Answer:
so you have a http request which is a promise and will wait until the data is received and from your example I can see you are implementing a loading screen kind of thing until the http request is completed.
To ensure the bulky http request doesn't time out you can use.
angular.module('MyApp', [])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.timeout = 5000;
}]);
While the page waits for the http request to complete you can use the scope variable($scope.loading = true;) to activate a loading spinner library to mask your page. Checkout angular loading overlay or some other code to do this.
Reference:
http timeout

Related

My AngularJS Service not Updating when User Click link with different $routeParams

I'm using a service in angularJS which gets a JSON object and passes it to a controller whenever a user clicks a specific link, /match/id-:matchId', it uses the $routeParams of the :matchId to select which JSON object to request.
The problem it once the user clicks one /match/id-:matchId' link and then tries going to another match with a different ID in the URL, the JSON object does not change, it remains the same. If the user refreshed the page, then they will get the correct JSON object on the page.
Here's the code:
var app = angular.module('app', ['ngRoute']); // TODO: 'ngAnimate', 'ui.bootstrap'
app.config(['$routeProvider','$locationProvider', function($routeProvider, $locationProvider){
$routeProvider
.when('/', {
templateUrl: '/app/static/home.html',
controller: 'mainController as mainCtrl'
})
.when('/match/id-:matchId', {
templateUrl: '/app/components/match/matchView.html',
controller: 'matchController as matchCtrl'
});
// use the HTML5 History API
$locationProvider.html5Mode(true);
}]);
app.controller('matchController', ['$routeParams', 'matchService', function ($routeParams, matchService) {
var matchCtrl = {};
var promise = matchService.getMatch($routeParams.matchId);
promise.then(function (data)
{
matchCtrl.match = data;
});
}])
app.service("matchService", function ($http, $q)
{
var deferred = $q.defer();
function getMatch(matchId) {
var url = 'https://jsonplaceholder.typicode.com/posts/' + matchId;
return $http({
method: 'GET',
// cache: true,
url: url,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
}).
then(function(response) {
//your code when success
// lgTblCtrl.amateurTable = data;
deferred.resolve(response);
console.log('SUCCESS!');
}, function(response) {
//your code when fails
console.log('ERROR!');
deferred.reject(response);
});
return deferred.promise;
}
this.getMatch = getMatch;
})
There are no console errors but when I put breakpoints in the chrome source panel I can see that when the user refreshes the page the code get's called in a different order. This is the order specific lines of code are run depending on how the user landed on a page, by clicking a button or refreshing the page:
Browser Refresh
var promise = matchService.getMatch($routeParams.matchId);
return deferred.promise;
deferred.resolve(response);
matchCtrl.match = data;
Click On A Link
var promise = matchService.getMatch($routeParams.matchId);
return deferred.promise;
matchCtrl.match = data;
deferred.resolve(response);
I'm new to AngularJS, What am I missing here?
This looks like an issue with your deceleration of your 'deferred' variable. The promise is returned correctly the first time, but then it resolves right away whenever the function is called again as the promise is resolved the first time.
Try the following to see if it fixes your issue, moving the declaration of the promise into the function:
app.service("matchService", function ($http, $q) {
function getMatch(matchId) {
var deferred = $q.defer();
var url = 'https://jsonplaceholder.typicode.com/posts/' + matchId;
return $http({
method: 'GET',
// cache: true,

Correct method to Redirect from $http.post in angularjs

Can you tell me what is the correct way to redirect to another page if $http.post returns a specific error code.
Just to add context, I want to redirect to another page if the user is not logged in or authorized to use the API.
function getData(filter) {
var deferred = $q.defer();
var data = JSON.stringify(filter);
$http.post('/myapp/api/getData', data)
.success(function (data, status, headers, config) {
deferred.resolve(data);
})
.error(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
You could do a redirect to the page using $window.location.href, based on the error condition you have.
var app = angular.module("sampleApp", []);
app.controller("sampleController", [
"$scope",
'$window',
'sampleService',
function($scope, $window, sampleService) {
sampleService.getData().then(function(result) {}, function(error) {
if (error.statusCode === 400) {
alert("Error");
$window.location.href = "http://stackoverflow.com"
}
});
}
]);
app.service("sampleService", function() {
this.getData = function() {
var promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject({
statusCode: 400
});
}, 1000);
});
return promise;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-App="sampleApp">
<div ng-controller="sampleController">
</div>
</div>
The best way to catch global AuthenticationErrorin angular is with interceptor.
This way you can monitor all request that are sent from angular and check for AuthenticationError.
$provide.factory('AuthErrorInterceptor', function($q, $location) {
return {
'responseError': function(rejection) {
//check for auth error
$location.path('/login');
return $q.reject(rejection);
}
};
});
Example :
$http.post('/myapp/api/getData', data)
.then(function (data) {
if(data.ErrorCode==1)
{
$window.location.href="controllerName/actionName";
}
})
Use a interceptor service in order to centralize all of your rejection request in the same service.
module.config(['$httpProvider', ($httpProvider: ng.IHttpProvider) => {
$httpProvider.interceptors.push('errorService');
}]);
module.factory('errorService', ['$location', function($location) {
var errorService = {
responseError: function(rejection) {
if (rejection === '401') {
$location.path('/login');
}
}
};
return errorService;
}]);
The $http.post is misguiding.
So far the best answer is #Kliment's. Interceptors are the best way to manage what comes before and after http requests.
However, if your end goal is to prevent access to a page, you have to at least use a routing plugin (ngRoute, ui-router) because with the promise idea there will always be a delay between the http request and the response.
Depending on server response time you'll still see the page display for about a second or so.
With ui-router you simply configure a resolve method for each state you want to protect. It could look like this:
.state('protected',
{
url : '/protected_page',
templateUrl : 'secret.html',
resolve: {
loggedin: loggedin
}
})
loggedin refers to a function you define that contains your $http.post call (or better yet a service)
function loggedin($timeout, $q, $location, loginService) {
loginService.then(function(data) {
if(data.status == 401) {
//$timeout(function() { $location.path('/login'); });
return $q.reject();
} else {
return $q.when();
}
});
}
Here this particular service returns a 401 status but you can return anything.
The state will not be resolved (and the page not displayed) until it's accepted or rejected.
You can redirect directly from there if you want, although it's not very elegant.
ui-router gives you another option with default redirection:
if (tokenIsValid())
$urlRouterProvider.otherwise("/home");
else
$urlRouterProvider.otherwise("/login");
With otherwise you tell ui-router to go to certain urls if no state exists for a particular request or if a resolve has been rejected.
On another subject, your http request is badly written.
.success and .error are deprecated and you don't need to create a promise ($q) over an $http request that itself already returns a promise.
You have a good example in the documentation linked above.
You can redirect to page on unauthorized access of a user based on the status code which you can return from your API call.
$http({
method: "POST",
url: 'Api/login',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
}).success(function (data,status) {
if(status==200){
alert('Successfully logged in');
$location.path('/dashboard'); //You can use this if you are defined your states.
}
}).error(function (data,status) {
if(status==403||status==403){ //Based on what error code you are returning from API
$location.path('/login');// if states are defined else
$window.location.href = "https://www.google.com";
}
});
First of all Nice Question , In this scenario You Can use $location , $state If it is external url You can use $window.location.href ... I would recommend $location and it is the best way ...
Please See the link for further Using $window or $location to Redirect in AngularJS
function getData(filter) {
var deferred = $q.defer();
var data = JSON.stringify(filter);
$http.post('/myapp/api/getData', data)
.success(function (data, status, headers, config) {
deferred.resolve(data);
if(data.errorcode==9999) // Define Your Error Code in Server
{
$location.path('/login'); // You Can Set Your Own Router
} })
.error(function (error) {
$location.path('/login'); // You Can Set Your Own Router
deferred.reject(error);
});
return deferred.promise;
}
Preferably use $location or $state ...

Angular - load data at app start and use in controller in different module

I'm pretty new with Angular and I'm stuck on this for a few days now :(
I have a web app (kind of portal with several web tools available).
I want to load some data from DB when the app being initially accessed and use the data in some controller (.i.e. load the data only once).
This is what I have by now:
Main app
var myApp= angular.module('MyApp',['ngRoute','ngTable','mpcApp','registerApp','forgotPasswordApp','tool1App','loginApp','userManagementApp','init']);
myApp.config(['$routeProvider','$locationProvider',function($routeProvider) {
$routeProvider.
when('/...', {
templateUrl: 'js/....html',
controller: 'tool1Ctrl'
})....
I also have myApp.run - but I will describe it later.
I've created different module for my factory:
(function (angular) {
var initApp = angular.module('init',[]);
initApp.factory('EndPoints', ['$http', function($http) {
var EndPointsList="";
return{
getList: function(){
$http.post("/getEndPoints", {
transformRequest : angular.identity,
headers : {'Content-Type' : undefined}
}).
success(function(data, status, headers, config) {
EndPointsList = data;
console.log(EndPointsList);
return EndPointsList;
}).error(function(data, status, headers, config) {
console.log("Failed to load end-points list");
});
return EndPointsList;
}
};
}]);
})(angular);
What I did next is injecting this factory into myApp.run:
myApp.run(['$rootScope', '$location', 'SessionIdService','EndPoints', function($rootScope, $location, SessionIdService,EndPoints) {
$rootScope.EndPoint= EndPoints.getList();
console.log("Current end-point: " + $rootScope.appEnv);
...
This is just not working! I don't see the print in console at all, and when I try to use the $scope.EndPoint in another controller in another module it appears to be empty.
Controller code:
var Tool1Controllers= angular.module('tool1App',[]);
Tool1Controllers.controller('toolCtrl', ['$scope', '$http','$rootScope', function ($scope, $http,$rootScope) {
console.log("Test: Controller end-point: " + $scope.EndPoint);
Please help! :(
The problem seems to be that you are returning a string before $http promise is fulfilled. You need to wait for the http response before returning data, or return the promise and let the consumers implement the outcome handlers.
Try updating your factory as follows:
initApp.factory('EndPoints', ['$http', function($http) {
return{
getList: function(){
return $http.post("/getEndPoints", {
transformRequest : angular.identity,
headers : {'Content-Type' : undefined}
});
}
};
}]);
And your run assignment as:
EndPoints.getList()
.success(function(data, status, headers, config) {
$rootScope.EndPoint= data;
}).error(function(data, status, headers, config) {
console.log("Failed to load end-points list");
});
UPDATE: An alternative to attaching data to the $rootScope is to have the factory cache the data and offer a method to return the data either from cache or from the remote endpoint if it hasn't already been cached:
initApp.factory('EndPoints', ['$http', '$q', function($http, $q) {
var endpoints = null;
return{
getList: function() {
return endpoints ?
// if data is already cached, return it
$q(function(resolve, reject) { resolve(endpoints); }) :
// otherwise fetch it from the service, cache it and return it
$http.post("/getEndPoints", {
transformRequest : angular.identity,
headers : {'Content-Type' : undefined}
}).then(function(data) { endpoints = data; return data; });
}
};
}]);
And now in your controllers, you can just inject the service and define outcome handlers for the getList promise:
.controller ...
EndPoints.getList()
.then(function(data) {
$scope.someVariable = data;
}, function(error) {
console.log("Failed to load end-points list");
});
...
Since factories are singletons, you can inject the Endpoints service into any number of controllers and the same cached data should be returned so that at most 1 call to the remote endpoint is made.

AngularJS Resolve a route based on a service promise

I am using ngRoute and and trying to get my routes to resolve based on the result of a function in a service I have defined
My service is as follows:
app.factory('AuthService', function ($q,$location,$http) {
var isLoggedIn = false;
return {
hasLoginSession: function(){
var defer = $q.defer();
if(isLoggedIn) {
//User has a valid session from a previous GetSession.json request
defer.resolve(isLoggedIn);
} else {
return $http.get('/session/GetSession.json').success(function(data, status, headers, config) {
isLoggedIn = data.success;
if(isLoggedIn) {
defer.resolve(isLoggedIn);
}
else {
defer.reject("EX_LOGIN_SESSION_IS_UNKNOWN");
}
}).
error(function(data, status, headers, config) {
isLoggedIn=false;
defer.reject("EX_LOGIN_SESSION_IS_UNKNOWN");
});
}
return defer.promise;
}
};
});
So as you can see I just have a simple session check function which sets a property based on the result of a http request.
I then have the routing setup like so, with a resolve just on the route path for testing at the moment:
var app = angular.module('pinpointersApp', ['ngRoute']);
app.config(
function($routeProvider,$httpProvider) {
//$httpProvider.interceptors.push(interceptor);
$routeProvider.
when('/login', {
templateUrl: 'login.html',
controller: 'LoginController'
}).
when('/map', {
templateUrl: 'partials/map.html',
controller: 'MapController'
}).
when('/locations', {
templateUrl: 'partials/locations.html',
controller: 'LocationsController'
}).
when('/', {
templateUrl: 'partials/locations.html',
controller: 'LocationsController',
resolve: {
checkSession: function ($q,AuthService) {
//var defer = $q.defer();
//defer.reject("EX_LOGIN_SESSION_IS_UNKNOWN");
//return defer.promise;
return AuthService.hasLoginSession();
}
}
});
});
app.run(['$rootScope', 'AuthService', function ($rootScope, AuthService) {
$rootScope.$on("$routeChangeError", function (event, current, previous, error) {
console.log(error);
//Perform other stuff here, e.g. redirect to login view
});
}]);
The server side request is being made, and I am seeing a pause in the view loading until the response is received. In my test I am returning a fail case and so reject the state of the promise in order to cause the $routeChangeError to be fired, but it never does and my view continues to load.
If I use the commented out lines of test code in my resolve block instead of my service routine call, so
resolve: {
checkSession: function ($q,AuthService) {
var defer = $q.defer();
defer.reject("EX_LOGIN_SESSION_IS_UNKNOWN");
return defer.promise;
//return AuthService.hasLoginSession();
}
}
then the routeChangeError event is fired, so what am I missing in order to just use the result of my service routine call?
OK, I figured out what I did wrong, in my service I had one too many return statements, I just needed to remove the return keyword before my opening $http request and now it works as required.

Where in angular should I put this code?

I have an http-method that gets some data from a google spreadsheet. I want to add this to the $scope so I can output it in the DOM. Later I might make a timed loop of this so that the $scope get's updated every 5 seconds or so.
I currently run the code in app.run:
angular.module('spreadsheet2angular', []).
run(function($http){
$http({method: 'GET', url: 'http://cors.io/spreadsheets.google.com/feeds/cells/0Aq_23rNPzvODdFlBOFRYWlQwUFBtcXlGamhQeU9Canc/od6/public/values?alt=json'}).
success(function(data, status, headers, config) {
var entries = data.feed.entry;
var phraces = [];
entries.forEach(function(entry){
var cell = entry.gs$cell;
if(!phraces[cell.row]){
phraces[cell.row] = {};
}
if(cell.col == 1)
{
phraces[cell.row].name = cell.$t;
}
else if(cell.col == 2)
{
phraces[cell.row].value = cell.$t;
}
});
phraces.forEach(function(phrace){
console.log(phrace);
});
}).
error(function(data, status, headers, config) {
console.log('error');
});
});
I'm new to angular, is this the best place to run it? I would like to run it as something that is easily reusable in different projects.
I think from what you've explained, a service would be perfect. Build it out then inject it in your controller. You can then call/use that service object whenever you would like.
I would use service/factory that returns promise. So we call async service method, get back promise and parse response into controller.
If you think to use the same call in the future, you can write generic method.
By the same way, if you are going to parse response by the same way in the future, the part of logic I would put into the service as well and wrap with $q . So the response still will be promise.
And this is an example I use that might help you to understand what I'm meaning:
app.service('apiService', ['$http', '$q', '$rootScope',
function($http, $q, $rootScope) {
var request = function(method, data) {
var deferred = $q.defer();
var configHttp = {
method: 'POST',
url: config.api + '/' + method
};
if (data !== undefined) {
configHttp.data = data;
}
$http(configHttp).success(function(data, status, headers) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
}).error(function(data, status, headers) {
deferred.reject(data);
});
return deferred.promise;
}
return {
getItem: function() {
return request('get_item');
},
getItemByParams: function(id) {
return request('get_item_by_params', {id: id});
}
};
}
]);

Resources