Code changes not taking effect until refresh/reload is clicked - angularjs

Any time I make changes to the code in my angularjs site, they do take effect until the user clicks the refresh button. Even if I log out to a page that is not angular then log back in it is the same old code until I click the refresh button. So if someone logs in it is the same as the last time they logged in regardless of changes and I obviously can't expect them to click refresh every time they log in.
So my question is how could I force a refresh of the code. I don't want to use window.reload or anything like that if there is a speacial angular way to accomplish this. I have tried clearing the template cache but it doesn't work. This is what I tried:
.run(function($rootScope, $templateCache) {
$templateCache.removeAll();
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (typeof(current) !== 'undefined'){
$templateCache.remove(current.templateUrl);
}
});
})

My problem turn out to be the browser caching js files. I didn't think that would be the problem because prior to using angularjs I never had this problem. So to fix the issue I found this: How to force browser to reload cached CSS/JS files? and modified it a little so I didnt have to use all the url rewriting.
I added the php function
function get_version($file){
return filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
}
Then where I link my scripts I use:
<script src="/path/to/script.js?<?php echo get_version('/path/to/script.js');?>"></script>

Related

Angular change URL on page load

I'm creating a schedule for a convention and would like to have the URL change during the convention time. If the user loads the page on Saturday of the con, the URL should change to [URL]?day=saturday.(The URL will also change when the user clicks to view different day)
I'm running into an issue on page load only, where the history.replaceState is causing
angular.js:13920 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
So I came across a forum that says to use something like
$location.path('/').search('day='+day).replace();
But it comes out as
/#/?day=saturday
I don't want the /# in the URL. So I found forums explaining to use $locationProvider.
I even added in the
app.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})
And it still says $locationProvider is not defined. I don't know what I'm doing wrong or if this is even the right direction to be going in. I just want to change the ?day=day_here when the page loads and when the user clicks to change the day.
Capture the route change on click when routing and replace the url. For the error use and your syntax seems to be right
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
But if you want to persist the url change you will have to do the changes to url in the routeChange
.run(function($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function(next, current) {
//... you could trigger something here like replacing the actual url ...
//$location.path('/').search('day='+day).replace();
});
})
Alternatively you can also look at https://github.com/angular-ui/ui-router as an alternative and do the changes to $location.url().replace() in onEnter or resolve options of state definition https://github.com/angular-ui/ui-router/wiki
If you want to use ngRouter and still getting the error a plunkr code for demo will surely help debug better.

Loading message shown on $routeChangeStart disappears as soon as LESS CSS starts compiling

I've created a pretty heavy AngularJS application which has many dependencies (JS libraries and LESS css). When the application URL is hit, it determines the route based on login status and redirects to login route if not logged in. The problem is, until the route is redirected to, and the HTML is loaded, the page remains completely blank for almost 4-5 seconds, which looks really confusing.
I tried to implement some message using $routeChangeStart but it's not giving me the desired results. I want the 'loading..." message as soon as URL is hit and until app is routed and HTML is fully loaded. But the message is disappearing after a couple of milliseconds.
$rootScope.$on('$routeChangeStart', function() {
$rootScope.layout.loading = true;
});
$rootScope.$on('$routeChangeSuccess', function() {
$rootScope.layout.loading = false;
});
UPDATE: The problem seems to be the LESS CSS which is being compiled and loaded to get the page ready. The loading indicator text correctly works without LESS CSS (see this Plunker)
In the actual application, I have put the loading indicator text after the body tag, and there are many JS scripts (including LESS.js) after the indicator text. The loading indicator shows until LESS starts compiling, and disappears as after compilation starts. Any solution to this?
I believe .run() method of angular can solve your issue, Run blocks are the closest thing in Angular to the main method. A run block is the code which needs to run to kick start the application. It is executed after all of the services have been configured and the injector has been created.
You can try the following to show/hide loader when your application is loading.
.run(['$location', function ($location) {
// if your application URL os https://myApplication/Login/loginStatus
if ($location.path() === '' && $location.$$absUrl.indexOf('/loginStatus') > -1) {
// show loading
// some code here to return route based on login status for example,
var promise = getLoginStatus();
promise.then(function (result) {
// redirect to the route as per login status
$location.path(result); //Where result is route url.
// hide loading
});
}
}]);

Get the url that a user is coming from AngularJS

If an user is coming from an specific page i need to do get some values out of a cookie and change what the users sees.
Now, the issue is that i cannot find a way to view what page the user is coming from.
EDIT: This is intended to capture when the users clicks back in a page and save the state of the previous page.
Any ideas?
Thanks in advance
Solved. Every time i load a page i'm saving the url, so when i get to this page i just have to read it to tell. Thanks!
You can use browser history in our javascript or you can write your last page in cookies and get the last link then update it
Using cookies will indeed fix this for you. So when a user goes to a new page - set a cookie like:
app.controller('myController',['$scope', '$location', $cookies], function($scope, $location, $cookies){
if($cookies.get('page') == '/index'){
//do stuff if user came from index
}
$scope.pageChanged = function(value){
$cookies.put('page', value);
$location.path('/index');
}
}
just make sure you use the pageChanged function to set your page every time user changes pages.
Using the $routeProvider you can use the resolve function to detect when a new route has been loaded.
Another way would be to listen for the event $routeChangeSuccessor $routeChangeError and get the information needed from the service $location or $route.
If you want a sample just ask me, I'll try to post one as soon as I have free time.

Clear History and Reload Page on Login/Logout Using Ionic Framework

I am new to mobile application development with Ionic. On login and logout I need to reload the page, in order to refresh the data, however, $state.go('mainPage') takes the user back to the view without reloading - the controller behind it is never invoked.
Is there a way to clear history and reload the state in Ionic?
Welcome to the framework! Actually the routing in Ionic is powered by ui-router. You should probably check out this previous SO question to find a couple of different ways to accomplish this.
If you just want to reload the state you can use:
$state.go($state.current, {}, {reload: true});
If you actually want to reload the page (as in, you want to re-bootstrap everything) then you can use:
$window.location.reload(true)
Good luck!
I found that JimTheDev's answer only worked when the state definition had cache:false set. With the view cached, you can do $ionicHistory.clearCache() and then $state.go('app.fooDestinationView') if you're navigating from one state to the one that is cached but needs refreshing.
See my answer here as it requires a simple change to Ionic and I created a pull request: https://stackoverflow.com/a/30224972/756177
The correct answer:
$window.location.reload(true);
I have found a solution which helped me to get it done. Setting cache-view="false" on ion-view tag resolved my problem.
<ion-view cache-view="false" view-title="My Title!">
....
</ion-view>
Reload the page isn't the best approach.
you can handle state change events for reload data without reload the view itself.
read about ionicView life-cycle here:
http://blog.ionic.io/navigating-the-changes/
and handle the event beforeEnter for data reload.
$scope.$on('$ionicView.beforeEnter', function(){
// Any thing you can think of
});
In my case I need to clear just the view and restart the controller. I could get my intention with this snippet:
$ionicHistory.clearCache([$state.current.name]).then(function() {
$state.reload();
});
The cache still working and seems that just the view is cleared.
ionic --version says 1.7.5.
None of the solutions mentioned above worked for a hostname that is different from localhost!
I had to add notify: false to the list of options that I pass to $state.go, to avoid calling Angular change listeners, before $window.location.reload call gets called. Final code looks like:
$state.go('home', {}, {reload: true, notify: false});
>>> EDIT - $timeout might be necessary depending on your browser >>>
$timeout(function () {
$window.location.reload(true);
}, 100);
<<< END OF EDIT <<<
More about this on ui-router reference.
I was trying to do refresh page using angularjs when i saw websites i got confused but no code was working for the code then i got solution for reloading page using
$state.go('path',null,{reload:true});
use this in a function this will work.
I needed to reload the state to make scrollbars work. They did not work when coming through another state - 'registration'. If the app was force closed after registration and opened again, i.e. it went directly to 'home' state, the scrollbars worked. None of the above solutions worked.
When after registration, I replaced:
$state.go("home");
with
window.location = "index.html";
The app reloaded, and the scrollbars worked.
The controller is called only once, and you SHOULD preserve this logic model, what I usually do is:
I create a method $scope.reload(params)
At the beginning of this method I call $ionicLoading.show({template:..}) to show my custom spinner
When may reload process is finished, I can call $ionicLoading.hide() as a callback
Finally, Inside the button REFRESH, I add ng-click = "reload(params)"
The only downside of this solution is that you lose the ionic navigation history system
Hope this helps!
If you want to reload after view change you need to
$state.reload('state',{reload:true});
If you want to make that view the new "root", you can tell ionic that the next view it's gonna be the root
$ionicHistory.nextViewOptions({ historyRoot: true });
$state.go('app.xxx');
return;
If you want to make your controllers reload after each view change
app.config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
$ionicConfigProvider.views.maxCache(0);
.state(url: '/url', controller: Ctl, templateUrl: 'template.html', cache: false)
cache: false ==> solved my problem !
As pointed out by #ezain reload controllers only when its necessary. Another cleaner way of updating data when changing states rather than reloading the controller is using broadcast events and listening to such events in controllers that need to update data on views.
Example: in your login/logout functions you can do something like so:
$scope.login = function(){
//After login logic then send a broadcast
$rootScope.$broadcast("user-logged-in");
$state.go("mainPage");
};
$scope.logout = function(){
//After logout logic then send a broadcast
$rootScope.$broadcast("user-logged-out");
$state.go("mainPage");
};
Now in your mainPage controller trigger the changes in the view by using the $on function to listen to broadcast within the mainPage Controller like so:
$scope.$on("user-logged-in", function(){
//update mainPage view data here eg. $scope.username = 'John';
});
$scope.$on("user-logged-out", function(){
//update mainPage view data here eg. $scope.username = '';
});
I tried many methods, but found this method is absolutely correct:
$window.location.reload();
Hope this help others stuck for days like me with version: angular 1.5.5, ionic 1.2.4, angular-ui-router 1.0.0

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