AngularJS with ui.router: reload page when clicking the same state link - javascript

I just got a request from our QA team, which I think sounds ridiculous. Here it goes: suppose you are already on the 'about' state/page in the angular-based app, and when you click on the 'about' state url again from the top menu, you want the 'about' page to reload. The about page does not fetch data from anywhere, by the way, a reload is simply equivalent to a blink.
For the state config in my angular app is like this:
.state('about', {
url: '/about',
templateUrl: '/path/to/about.html',
controller: 'aboutCtrl as aboutView'
});
And in the top menus, we have a link pointing to this state:
<a ui-sref="about">About</a>
I have tried many things to get this to work: clicking the link triggers the reload of the same state.
Things like $state.go('about', {}, {reload: true}); or $state.transitionTo('about', {}, {reload: true}); don't work, because the links are static.
One last resort I am currently trying is to manipulate the reload thing in the run phase of Angular by listening to '$stateChangeSuccess' event, but I don't think it will work, because there's no state change at all if you click on the 'about' link while you are right on that state.
Is there any ways to work around this? Thanks

There is an option attribute called ui-sref-opts that comes with the UI Router. I faced the same problem and it solved it.
Eg: <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
Docs URL : UI Router DOcs

You're right, I can't get any state change events to fire either once already in that state. Until, and if that functionality becomes available to use through that api someday, here's a semi-hacky solution for this. We can just leverage ng-click and use some silly logic to appease QA (in your case). Also, I don't know your controller implementation, so I placed my suggestion on $rootScope in .run in this example for simplicity and visibility, but integrate accordingly if you choose to do so. Observe the following example...
<a ui-sref="about" ng-click="sillyQA()">About</a>
.run(['$rootScope', '$state', function($rootScope, $state) {
$rootScope.sillyQA = function() {
if($state.current.name === 'about') {
$state.go('about', {}, { reload: true });
}
}
// -- just to see our about => about state 'change'
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
console.log('toState: ' + toState.name );
console.log('fromState: ' + (fromState.name || 'Just got there! click again!'));
})
}]);
JSFiddle Link - demo

Related

ui-router: Reset $state without using $state.go()

First off, I think the overall issue here is that AngularJS still doesn't have a sensible, best practice way of "restarting" the app and all its components. So far, the best practice seems to be setting the path to a "default" view, and then reloading the window. We do this in our /logout state, as seen here:
$stateProvider.state('logout', {
onEnter: function($state, $window, store) {
//Remove any session variables
store.remove('varA');
store.remove('varB');
//"Logout" the user
$state.go('login');
$window.location.reload();
}
})
However, this is a bad user experience. The user can actually see the view change and the components on the page shift before the window reloads. It just seems very buggy overall.
Originally, we did not include $state.go('login'), and did not get the weird experience of seeing the view change before logout. However, when we started using $state handlers like $rootScope.$on('$stateChangeStart', function (event, toState, toParams), we noticed that toState was not being reset after the window reload. So $stateChangeStart would trigger after the reload, and toState would still be set to whatever view the user was on before calling /logout. This isn't a true app reset!
Possible Solution: I think all of this can be solved if there was a way to "reset $state" without using the $state.go() method...something that happens behind the scenes instead.
Simple code change fixed it for me
//"Logout" the user
$state.go('login', null, {notify: false}).then(function() {
$window.location.reload();
});
Source: https://github.com/angular-ui/ui-router/issues/2486#issuecomment-180872463

Remove / cancel animations in ui router when navigating back and forth

I'm using AngularJS ui router and I have about 3 pages in total. The problem I am facing is that on the home page (first page) I have an intro animation which lasts about 10 seconds in total. The intro animation is attached to the directive.
Now once I land on that page, the intro starts and everything is fine until I navigate to another page - it seems that the intro keeps playing as if the DOM and in particular - the directive was not removed properly.
Is there a way to remove / clear DOM before navigating to another page?
The code is massive to post here and I was wondering if there is a quick fix for this? If not, I will try to post it on jsfiddle.
Mabe something like this will help
.run(function($rootScope, $route, $location) {
$rootScope.$on("$stateChangeStart", function (ev, to, toParams, from, fromParams) { {
//to.name is new state name
//from.name is old state name
TweenMax.killTweensOf($("#yourId"));
});
});

$state.go doesn’t redirect to given path

i've got a view that's outside of my tabs, now when i try to redirect from that view to a tab i get redirected to the wrong tab. i've made a codepen to show you what i mean since i don't really know how to explain it well see the logs i create in the console
.controller('MyCtrl', function($scope, $state, $rootScope, $ionicPlatform) {
$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
// do something
$scope.from = fromState;
console.log(fromState);
})
$scope.goBack = function(){
console.log($scope.from.name);
$state.go($scope.from.name);
}
})
Codepen
You should apply the other answers but you have another problem.
The other problem is that, when you click on back button the state is changing to tab.volgend (which is right) but after this is going to tab.alert state... so I'm trying to figure out why is this second redirect happening.
Extract from console.log when clicking back button:
My first candidate is:
$urlRouterProvider.otherwise('/tab/alerts');
You shouldn't use ui-route with standard routing, so you should comment this line an add the next in your controller:
console.log('going to default state');
$state.go('tab.alerts');
EDIT
The second transition is made by the ionic framework, I have put a breakpoint and check the callstack, check this captures:
1- first call when back is clicked:
2- The ionic framework detects a change in the url and.. fires the second transition:
I'm going to read more this framework to see if I understand why is this happening... I keep you updated.
You should pass the name of the state to $state.go(), not the state object.
So $state.go($scope.from.name) should solve this for you.
why not simply use
$state.go('stateName', {//for stateParams}, { reload: true });
This happened with me too. Try transitionTo method, instead of go
$state.transitionTo($scope.from.name);
This worked out in my case.
More details can be found here
Edit : I forked your original codepen and it worked there too.. Forked Codepen here

AngularJS $stateParams when using reloadOnSearch:false

I have a page in my application which uses a search so i have added the "realoadOnSearch:false" which works perfectly
The problem I have is when navigating to the same state with a different stateParam:
when I navigate to #/category/20/ from any other page it works fine... i then have a link on that page to #/category/3 (the parent category for 20) and the URL updates, however the content does not (no console errors)
app.js (main application)
.state('category', {
url: '/category/:categoryId/',
templateUrl: '/Home/Category',
controller: 'categoryCtrl',
reloadOnSearch: false
})
I have tried adding target="_self" to force page reload and it does not work
I have also tried to watch $stateParams for changes and there is nothing
Clicking the link to #/category/3 from #/category/20 (and vice versa) should navigate to the new page and reload the data, where search should NOT reload the page (latter works but not the former)
The URL is prefered to be a ng-href rather than ng-click as it is managed by the root controller
EDIT:
I did not find a direct solution, however i just disabled the reloadOnSearch and my sorting buttons still work so this works for me for now as a solution.
The problem is that reloadOnSearch doesn't do what you think it does; it's actually more like reloadOnStateParams. Setting it to false prevents you from making state changes where only the stateParams change, which is what you're doing here (going from #/category/3 to #/category/20).
You can see this documented on the UI router issues page: https://github.com/angular-ui/ui-router/issues/1079
There's some workarounds in there but none of them are great. You are probably best off using an ng-click that forces a reload manually, something like this:
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});

angularjs - refresh when clicked on link with actual url

I use routeProvider to define controlers and templates for my urls.
When I click on the link, which has the same url as is the actual location, nothing happens. I would like the reload() method to be called if a user clicks on such a link even if the location hasn't changed. In other words, if I set the location to the same value, I would like it to behave the same as if I would set it to different value.
Is there a way to configure routeProvider or locationProvider to do it automatically? Or what is the right approach to do this? This is stadard behaviour in round trip applications, but how to do it in angularjs?
I've asked it on google groups as well.
UPDATE:
This question is getting lots of views, so I will try to explain how I solved my problem.
I created a custom directive for linking in my app as Renan Tomal Fernandes suggested in comments.
angular.module('core.directives').directive('diHref', ['$location', '$route',
function($location, $route) {
return function(scope, element, attrs) {
scope.$watch('diHref', function() {
if(attrs.diHref) {
element.attr('href', attrs.diHref);
element.bind('click', function(event) {
scope.$apply(function(){
if($location.path() == attrs.diHref) $route.reload();
});
});
}
});
}
}]);
The directive is then used for all links in my app I want to have this functionality.
<a di-href="/home/">Home</a>
What this directive does is that it sets the href attribute for you based on di-href attribute so angular can handle it like always and you can see the url when you hover over the link. Furthermore when user clicks on it and the link's path is the same as the current path it reloads the route.
Add a / (slash) to the defined url in the route configuration
I met a similar problem today, I have a link in my web page and when I click it, I want the ng-view reload each time, so that I can refresh data from server. But if the url location doesn't change, angular doesn't reload the ng-view.
Finally, i found a solution to this problem. In my web page, I set the link href to:
test
But in the route config, I set:
$routeProvider.when('/test/', {
controller: MyController,
templateUrl:'/static/test.html'
});
The different is the last slash in url. When I click href="#/test" for the first time, angular redirect the url to #/test/, and load ng-view. when i click it second time, because the current url is #/test/, it's not equal to the url in the link (href="#/test") I clicked, so Angular triggers the location change method and reloads the ng-view, in addition Angular redirects the url to #/test/ again. next time i click the url, angular does the same thing again. Which is exactly what I wanted.
Hope this was useful for you.
You can add a _target='_self' on the link to forces the page to reload.
e.g.
{{customer.Name}}
Tested with version 1.0.5 and 1.2.15 on IE and Firefox.
Here's more information from AngularJS site :
Html link rewriting
When you use HTML5 history API mode, you will need different links in different browsers, but all you have to do is specify regular URL links, such as:
link
When a user clicks on this link,
In a legacy browser, the URL changes to /index.html#!/some?foo=bar
In a modern browser, the URL changes to /some?foo=bar
In cases like the following, links are not rewritten; instead, the browser will perform a full page reload to the original link.
Links that contain target element
Example: link
Absolute links that go to a different domain
Example: link
Links starting with '/' that lead to a different base path when base is defined
Example: link
you should use $route.reload() to force the reload.
I don't know if is there a 'automatic' way to do this, but you can use ng-click on these links
For people who are using AngularUI Router. You can use something like this:
<a data-ui-sref="some.state" data-ui-sref-opts="{reload: true}">State</a>
Notice the reload option.
Found the answer here: https://stackoverflow.com/a/29384813/426840
From #Renan Tomal Fernandes answer. following is an example
HTML
<a href="#/something" my-refresh></a>
JS
angular.module("myModule",[]).
directive('myRefresh',function($location,$route){
return function(scope, element, attrs) {
element.bind('click',function(){
if(element[0] && element[0].href && element[0].href === $location.absUrl()){
$route.reload();
}
});
}
});
I think it's a simpler approach.
.directive ('a', function ($route, $location) {
var d = {};
d.restrict = 'E';
d.link = function (scope, elem, attrs) {
// has target
if ('target' in attrs) return;
// doesn't have href
if (!('href' in attrs)) return;
// href is not the current path
var href = elem [0].href;
elem.bind ('click', function () {
if (href !== $location.absUrl ()) return;
$route.reload ();
});
};
return d;
});
Assuming You want to make all basic <a> links (without target attribute) reload on click and You use relative links in the href attribute (e.g. /home instead of http://example.com/home) You don't have to add any special markup to your HTML (comes handy when updating a site with HTML already written).
In my case if the url is same, nothing worked including $route.reload(), $location.path(), $state.transitonTo() etc.
So my approach was Using Dummy Page as follows,
if( oldLocation === newLocation ) {
// nothing worked ------------
// window.location.reload(); it refresh the whole page
// $route.reload();
// $state.go($state.$current, null, { reload: true });
// $state.transitionTo($state.current, $stateParams, {reload:true, inherit: false, notify: false } );
// except this one
$location.path('/dummy');
$location.path($location.path());
$scope.$apply();
}
You need to make '/dummy' module somewhere, the module doesn't do anything, it only change url so that next $location.path() can be
applied. Don't miss $scope.$apply()
I ran into this issue a moment ago, except for it was the home page '/'. I wanted a simple solution with less code. I just took advantage of the .otherwise method in the $routProvider
So in the html link looks like:
Home
since there is no '/home' page specified in the routProvider it will redirect to '/' via the 'otherwise' method. page with this set up:
.otherwise({
redirectTo: '/'
});
Hope it helps someone
I tried Wittaya's solution above using directive approach. Somehow the directive keeps throwing error. I end up with this solution
HTML
Devices
Controller
$scope.stateGo = function (stateName) {
if ($state.$current.name === stateName) {
$state.reload();
} else {
$state.go(stateName);
}
}
Just tried adding this
$(window).on('popstate', function(event) {
//refresh server data
});
and it works fine

Categories

Resources