Angularjs some routes slow to load - angularjs

I am having a very bizarre situation that I can't seem to figure out. Here are my routes:
$routeProvider.when(/application1/:type, {
templateUrl: "application1/index.html"
})
.when(/application1/:type/:folder, {
templateUrl: "application1/index.html"
})
.when(/application2, {
templateUrl: "application2/index.html"
})
.when(/application3, {
templateUrl: "application3/index.html"
});
For some reason when I use $location.path on application2 and application3 it works fine and updates right when i call it. However anytime I switch to anything on application1 it takes about 3-5 seconds, then starts to load. When I refresh the page on application1 it works right away so I don't think it is the code that is associated with it. How can certain routes behave so differently?
UPDATE: I ran a profiler on my application: It seems to be take 5+ seconds to run $apply and/or $digest when loading a route in application1. What can be ways for me to speed this process up?

I had the same problem that routing worked when starting but becomes slow at doing specific routes. Since it worked when started i thought $route.reload(); might do the trick.
$route.reload();
$location.path("application1/");
This fix worked for me. Don't ask me the detailed explanation though.

I just had this issue happen to me. It turns out it was because my function that was calling $location.url was called from jQuery ".on" (jQLite actually). I had forgotten about how with AngularJS if you are called from something outside the $digest cycle you need to call $applyAsync (or $apply) to do "AngularJS stuff". Maybe if it wasn't for my timeout timer it would have not worked at all (I think when that kicked off that's when the new view finally was processed).
The fix in my case was to change this (this is CoffeeScript but same sort of deal in pure JavaScript):
element.on 'hidden.bs.modal', () ->
stuffIncludingLocationUrlCall()
to this:
element.on 'hidden.bs.modal', () ->
scope.$applyAsync ->
stuffIncludingLocationUrlCall()
Now the view change from $location.url happens really fast.
Edit: Here's a Javascript & jQuery version for those that come across this, as I did...
$(element).on("click", function() {
// any processing or other logic you need goes here
$scope.apply(function() {
$location.path("new/path");
});
});

Related

angularjs - implement route's resolve feature without routing/ng-view

In a big application, i now need to access some data (json api call) from asynchronously (before, those data were accessed synchronously).
I would like not to have to change components implementation to now handle this async behaviour (too risky).
I thought about $routeProvider's "resolve" feature (with promises) that helps to abstract this async behaviour out from the components/controllers.
Unfortunately i am absolutely not using routing in any way.
Is there an implementation for that? If not, where could i start?
EDIT:
how i was before (jsonData were not loaded synchronously but it was transparent thanks to systemJS features, SystemJS, Which we are throwing in garbage now, hence the question):
https://plnkr.co/edit/BSreVYNAr7sijYwEpb5G?p=preview
How i am now:
https://plnkr.co/edit/WnX0ynOqkZsmEzIxl1SI?p=preview
Watch the console to see an example of the problems that can occur now.
I kind of made it work by going like that, but i'm not completely satisfied with it (watch the config block):
https://plnkr.co/edit/P9Rv6rnboFlaFZ0OARNG?p=preview
$provide.value('$provide', $provide);
$routeProvider.otherwise({
template: '<test></test>',
controller: function ($provide, myJsonData1) {
$provide.value('myJsonData', myJsonData1);
},
resolve: {
myJsonData1: function(){
return getMyJsonData();
}
}
});
Hope this helps :)

url/state changes not working after angular.copy called in a factory

I'm at my wits end on this one, so any help is greatly appreciated!
I've been making an angular/node/mysql app for the past few weeks and came across this issue. I have a database running mysql that stores a list of users and their information. I created an API to provide the front-end with access to user data for login and all that. The flow is as follows:
User enters new state where info on them needs to be preloaded:
.state('info', {
url: '/info',
templateUrl: 'views/info.html',
controller: 'InfoController',
resolve: {
postPromise: ['user', function(user) {
return user.loadInfo();
}]
The code is run in the user factory so that data is fetched before the page loads:
app.factory('user', ['$http', 'auth', function($http, auth) {
var user = {};
user.loadInfo = function() {
var userId = auth.currentUser();
return $http.get('/users/' + userId).success(function(data) {
angular.copy(data, user);
});
};
return user;
}]);
The page loads fine the first time. Then I navigate somewhere else via $state.go('home') or something, and when I try to return to the same page (/info) it sometimes doesn't work. What happens is I enter in the new url, and the browser basically ignores it and just shows the url of my current page.
Start at localhost:8080/#/home
Type in localhost:8080/#/info and go there
Works fine first time. Navigate to localhost:8080/#/home
Now at localhost:8080/#/home
Type in localhost:8080/#/info, and the browser ignores it, just displaying localhost:8080/#/home
I've tried commenting out angular.copy, and that seems to fix the issue, but I still need to copy the data over that I fetch from the server (which does successfully get transferred).
So my primary question is: Is there an alternative to angular.copy that I can use that will work here? I still find it weird that it is used in all the examples but is causing this issue here.
Secondary question: If angular.copy is the way to go, have any of you seen this issue and have a guess at what's causing it? Does something look off in what I'm doing?
Bonus Info: I don't know how quite to describe this, but sometimes if I wait long enough before going back to the problem url, it works... I notice that a call is made to the server right as I'm typing in the problem url (before even hitting enter) and when that happens, it seems work. It's intermittent though, and stops any $state.go() calls from working to that problem url if they are called through a button click.
Alright, I got the answer for this one and it's pretty dumb. "user" is an object inside of the factory and "loadInfo" is a function attached to user. When I did the angular.copy(), data from the server overwrote the loadInfo function so I couldn't use it again...
So yeah, that's solved.

AngularJs : using $location.path() to change the view but its taking some time to load

I am just doing a regular $location.path to load my template, which will hit my server and change the view.
The template changes simultaneously but the view is taking some time to load.
$scope.xxx= function () {
$location.path("xxxx");
}
Just to cross check I removed all the contents of my view(except a hello world) and also from my controller but I don't know what is going wrong in here.
.when('/xxx', {
templateUrl: '/users/xxx',
controller: ''
})
I was facing same problem $location.path taking time to load the page. I reload using $route.reload() after location.path this work for me.
Below I have mentioned the code that I used.
if (result.status === "invalid"){
$location.path('/basic-profile');
$route.reload();
}
Hope this works for you :).

rootScope functions not being called when using ngIdle

I am using the ngIdle library and as the documentation states there are certain methods that you can call to check for user inactivity, and I have put these on the root scope.
app.run(function($rootScope) {
$rootScope.$on('IdleTimeout', function() {
alert('you will be logged out');
});
$rootScope.$on('IdleStart', function () {
alert('test');
});
});
These functions are never being called and I think that it might be a problem more to do with $rootscope rather than the ngidle library.
There are not any errors in console, and the ngidle library is included correctly. Any Ideas?
For me ng-idle works fine using the $rootScope. But I wasted some time waiting for the events to fire until I recognized, that the configuration expects seconds instead of milliseconds ;)
app.config(function(IdleProvider) {
// configure Idle settings
IdleProvider.idle(5); // in seconds!
IdleProvider.timeout(5); // in seconds!
});
I spent some time struggling with this too; none of the events were firing at all. Turns out that you need to call Idle.watch() so that the timing starts.
This isn't well documented; documentation is patchy and none of the examples I saw had this. All looked just like the code you have so I couldn't figure out what's wrong until I saw it in the Getting Started section on the library's GitHub page. It's not explicitly mentioned though, you have to look closely.
.run(function(Idle){
// start watching when the app runs. also starts the Keepalive service by default.
Idle.watch();
});
Then the second catch: once you get auto-logged out once, it will no longer time your session if you login again without reloading the app. You need to call Idle.watch() again from your Login method to reset the timers and start again.

Add "intermediary" page prior to full page load Angular

My problem
I am using Angular to create a Phonegap application. Most of my pages are fairly small and the transition/responsiveness is quick and smooth. However I have one page that is fairly large that I am having an issue with.
The method for changing to this page is straightforward:
<button ng-click="$location.url('/page2')"></button>
When you "tap" the button above it takes about 1-2s to respond and change pages. I have double checked all areas for improvement on this page and determined that the delay is caused by Angular compiling and parsing the DOM of this page prior to changing the page. Please note that I am testing this on a real device so it is not due to emulator speeds.
The question
Is there a way to automatically or manually intercept page changes and put them in a sort of "loading" page so the response to the button click is immediate and page change is visible but the page content loads in a second or 2 later onto this "loading" page.
Its only an issue cause it is very awkward to click something and have nothing happen. I am having a very hard time finding any resources on this matter so if someone can even point me in the right direction to look I would be grateful.
Edit:
A super hacky solution I found was to use an ng-include on wrapper page and delay the include for a little bit.
myBigPageWrapper.html:
<div ng-include="page"></div>
Controller:
$scope.page = '';
setTimeout(function() { $scope.page='/pages/myBigPage.html'; $scope.$apply(); }, 1000);
Then navigate to your wrapper page instead: $location.url('/myBigPageWrapper')
This is obviously not ideal... But I hope this helps clarify what I am attempting to do.
Page2.html
This is the section that causes the page to slow down, commenting this out makes the page load very quickly. There are 13 pages in the "auditPages" array each containing about 50 lines of html mostly containing form input elements. Quite a bit of logic however it runs great once it is loaded. I am not going to include all the pages as it would be overload.
<div class="page-contents">
<form name="auditPageForm">
<div ng-repeat="(pageKey, pageData) in auditPages " ng-show="currentAuditPage.name==pageData.name">
<audit-form page="pageData">
<ng-include src=" 'partials/audit/auditSections/'+pageData.name+'.html'" onload="isFormValid(pageKey)"></ng-include>
</audit-form>
</div>
</form>
</div>
To sum up my comments above:
Your question was:
Is there a way to automatically or manually intercept page changes and
put them in a sort of "loading" page?
A lot of people asks for this question since Angular doesn't seem to provide a nice handling of a loading transition.
Indeed, the possible nicest solution would have been to "play" with the resolve property of angular's module configuration.
As we know, resolve allows to run some logic before the targeted page is rendered, dealing with a promise. The ideal would be to be able to put a loading page on this targeted page, while the resolve code is running.
So some people have nice ideas like this one:
Nice way to handle loading icon while route is changing
He uses $routeChangeStart event, so the loading icon would happen on the SOURCE page.
I use it and it works well.
Also, there is another way: make use of $http interceptor (like #oori answer above), to have a common code allowing to put a loading icon but...I imagine you don't want the same icon on every kind of http request the page does, it's up to you.
Maybe in the future, a solution would come directly associated to the resolve property.
Angular has $httpProvider.responseInterceptors
// Original by zdam: http://jsfiddle.net/zdam/dBR2r/
angular.module('LoadingService', [])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('myHttpInterceptor');
var spinnerFunction = function (data, headersGetter) {
angular.element(document.getElementById('waiting')).css('display','block');
return data;
};
$httpProvider.defaults.transformRequest.push(spinnerFunction);
}])
// register the interceptor as a service, intercepts ALL angular ajax http calls
.factory('myHttpInterceptor', ['$q','$window', function ($q, $window) {
return function (promise) {
return promise.then(function (response) {
angular.element(document.getElementById('waiting')).css('display','none');
return response;
}, function (response) {
angular.element(document.getElementById('waiting')).css('display','none');
return $q.reject(response);
});
};
}])

Resources