Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refreshing the browser doesn't refresh the ui-router's state when doing nested states. #105

Closed
CMCDragonkai opened this issue Apr 28, 2013 · 32 comments

Comments

@CMCDragonkai
Copy link

In a situation like:

                .state(
                    'blog',
                    {
                        abstract: true, //this state is abstract, it provides an abstract base for children (only abstract states can have a default child state)
                        url: '/blog',
                        templateUrl: 'blog.html',
                        controller: 'BlogCtrl'
                    }
                )
                .state(
                    'blog.posts',
                    {
                        url: '', //empty url demonstrates that it is the default childstate of the ui-view
                        templateUrl: 'blog_posts.html',
                        controller: 'BlogPostsCtrl'
                    }
                )
                .state(
                    'blog.post',
                    {
                        url: '/:blogPostId',
                        views: {
                            '': {
                                templateUrl: 'blog_post.html',
                                controller: 'BlogPostCtrl'
                            },
                            'comments': {
                                templateUrl: 'blog_post_comments.html',
                                controller: 'BlogPostCommentsCtrl'
                            }
                        }
                    }
                );

When you go into e.com/blog/123 and go back to e.com/blog by refreshing the browser or a location refresh, it doesn't change the state back to blog.posts. It does do it when I use the back button or hit on a link that changes the url, but a direct location refresh doesn't.

@ksperling
Copy link
Contributor

Can you provide this as a plnker or other working example? Navigating to http://angular-ui.github.io/ui-router/sample/#/contacts/1 and then manually changing the url to http://angular-ui.github.io/ui-router/sample/#/contacts works as expected in the sample app

@CMCDragonkai
Copy link
Author

It'd be difficult to do in plunker do it's navigation. I'm using HTML5 urls if that might help.

@laurelnaiad
Copy link

@CMCDragonkai -- if HTML5 mode is working for you would you please help me figure out how? I might be dense but I can't see them working... #116

@ksperling
Copy link
Contributor

@CMCDragonkai hard to say what's going on without seeing it in action...

@timkindberg
Copy link
Contributor

I bet this was the devil bug.

@jonathanadler
Copy link

Hi @CMCDragonkai,
I'm having the same problem.
The only difference is that I'm not using html5 mode.
Did you find a solution?

@CMCDragonkai
Copy link
Author

No I didn't. So it's left that way.

@jonathanadler
Copy link

I found this thread:
angular/angular.js#2431
which seems to be connected, since I've noticed that when I refresh, an $http.get request within my state resolve function, isn't being performed.
It didn't help me, but it could help you.

EDIT:
this is how my state code looks like:

state('settings', {
    abstract: true,
    templateUrl: '/app/view/settings.html',
    controller: 'SettingsController',
    resolve: {
        settings: settingsController.loadSetting
    }
}).state('settings.general', {
    url: '/settings/general',
    templateUrl: '/app/view/general_set.html'
}).state('settings.notification', {
    url: '/settings/notification',
    templateUrl: '/app/view/mail_set.html'
})

If you also have a resolve function that might be making all the trouble, you could try wrapping it's contents in a timeout. That's what finally helped me. I used a timeout since I've noticed that the state resolve function was called before my app.run was called.
I know it's kind of a hack, but it's the only thing fixing my problems at the moment.
I guess I'll get back to it in the future, and try to make it work better.
I'll probably have to change my state architecture a bit.

I hope this helps you, or someone else that will see this thread.

@jonathanadler
Copy link

Hey @eggers,

I think my problem was that some of the data I needed for the state's
resolve function hasn't been resolved itself.
To elaborate: On my app.run function, I get some data from the server and
save it in an object on the $rootScope.
Now, In my resolve function for this state, I needed access to this data,
but since I just refreshed the page, it hadn't been resolved yet.
So a timeout helped me on this one.
I think I could've added a service with a function returning a promise, and
that would've probably fixed it, but for the time being I left it with a
timeout.

If you want to investigate some more, I suggest you use ui-router's state
events to see where the flow is stopping.
You can find them here:
https://github.com/angular-ui/ui-router/wiki#wiki-state-change-events

You can add some console logs on the stateChangeStart and the
stateChangeSuccess to see where it stops, and also use the stateChangeError
to see if any errors have occurred on the resolve function (Notice that the
say that: "It's important to note that if you have any errors in your
resolve functions (javascript errors, non-existent services, etc) they will
not throw traditionally. You must listen for this $stateChangeError event
to catch ALL errors.").

Good luck!

I'll be glad to hear if you have any conclusions.

On Tue, Feb 4, 2014 at 10:15 PM, eggers notifications@github.com wrote:

@jonathanadler https://github.com/jonathanadler did you learn anything
more about this problem? I'm having the same issues right now.


Reply to this email directly or view it on GitHubhttps://github.com//issues/105#issuecomment-34101853
.

@eggers
Copy link

eggers commented Feb 4, 2014

@jonathanadler I had a different issue. I hadn't put the leading / on the urls for my states which didn't cause a problem when linking via ui-sref, but didn't work when I refreshed the page. Adding the leading / to the children states fixed the problem.

@keithharvey
Copy link

I had what looked like a similar problem. My service (called within a nested state's resolve) was resolving a promise immediately with a null value, resulting in a blank screen.

@bikashsharmabks
Copy link

angular.module('app').run(['$state', '$stateParams',
    function($state, $stateParams) {
        //this solves page refresh and getting back to state
}]);

This will solve the issue

@tthew
Copy link

tthew commented May 12, 2014

+1 @bikash1999's tip worked for me.

@talhamaniar
Copy link

while implementing "$locationProvider.html5Mode(true).hashPrefix('!');". When i refresh the page eg: url: localhost:8000 /project.
i am getting issue in page " NOT FOUND ". Any one can help me where i am wrong..

@zacronos
Copy link

@talhamaniar, this is most likely an issue with your backend setup, not with your angular code.

If you directly navigate to e.g. http://localhost:8000/project (even if you do it via refresh), your browser will make a request to your backend for the path /project. But if this is only defined as a route/state in your angular code, your backend won't know how to deal with it -- you probably only serve your webapp on a url like http://localhost:8000/index.html.

The solution is probably to get some sort of wildcard/catchall set up on your backend so that your webapp gets served on any URL that isn't a defined backend API call or some static resource.

@naveen2048
Copy link

@talhamaniar
I'm having issues when refreshing the page manually and loose all the routing and its the case as you mentioned and myapp is served on /index.html, which is the shell page

I have a login screen and on this event i'm checking if user is Authenticated and performing the logic of handling
$rootScope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
//Saving the instance of url's to service
commonService.seturls(newUrl, oldUrl);

    if (!AuthenticationService.isLoggedIn()) {
        // redirect back to login
        $location.path('/login');
    }
});

When I fire-up the app, its checks into the Authentication(I set a cookie value once the user is authenticated and set the value to cookie) and redirect the user to #/login if not authenticated. Once logged into the app can navigate through the links loading different views based on the route setup using ngRoute.

** The problem, when a user manually refresh the page, it redirect back to login and url changes to something like this

before refresh : http://localhost/Index.html#/dashboard
after refresh : http://localhost/dashboard#/login

If I do a refresh again on the it gives me 404 not found. I'm using WebAPI for DB operations

Please suggest, as I have a deadline and due for deployment to production and stuck with this issue

@zacronos
Copy link

zacronos commented Dec 4, 2014

@naveen2048 , it sounds like you are getting a mix of HTML5 and Hashbang behaviors, instead of just one or the other. (Go here and scroll down to the "Hashbang and HTML5 Modes" section to read more about this.)

Do you have something like this in your code somewhere? $locationProvider.html5Mode(true)? The default is for HTML5 mode to be false, which will leave you in Hashbang mode. Or maybe a better question -- do you want to use HTML5 mode or Hashbang mode? Or do you not care as long as it works?

There are 2 ways to fix your problem:

  1. The issue being discussed here comes from refreshing the page in HTML5 mode -- in order for that to work properly, you have to serve your webapp not just on Index.html, but also any paths you use in the app -- so that the webapp will get served on URLs like http://localhost/dashboard or http://localhost/login. That is one solution -- make sure you serve your webapp on any URL the browser might get. This isn't an angular/ui-router issue, this is a backend issue.

  2. If you can get your app to stay fully in Hashbang mode, then every URL in your webapp will be something like http://localhost/Index.html#something, in which case you don't need to do anything on the backend since you are always using Index.html in the URL.

@zeeshanjan82
Copy link

Thanks @zacronos as I understand the issue is when we setup the Html5 mode and do not have a hash (#) in the url. As per your comment if we are able to serve our webapp on any URL the browser might get , then this issue is fixed. But in Node how can we do that as with angular we just have a single file. Can anyone suggest me how can it be done with angular and node.

@zacronos
Copy link

zacronos commented May 6, 2015

@zeeshanjan82, sounds like you understand the problem. How to fix it will depend on how you have set up node to serve that single file, and whether you also have API calls or other URLs to handle.

If you are using Express.js on the server, the easiest thing to do (which may not always be best) is to add a wildcard route (/*) after adding all other routes, and have that new route serve your single file. That means if a request is made to your server for an unknown URL (such as a URL serviced in the browser by angular), instead of getting a 404 error, your server will blindly serve your single file.

@zeeshanjan82
Copy link

thanks @zacronos I am using gulp and its plugins like watch and browsersync , in my case how can I do it. Do I need to include some middleware in my gulp file as a task?

@zacronos
Copy link

zacronos commented May 6, 2015

@zeeshanjan82, the question is how the file gets into your browser. Are you running a node backend server like Express.js to serve the file on something like http://localhost/...? Or do you just access the file locally, via some URL that starts with file:///? Or are you uploading the file to a web hosting service somewhere?

@zeeshanjan82
Copy link

@zacronos I have not yet created the backend yet, I have the frontend app which is an angularjs app and I have configured the gulp to have the app run on the url http://0.0.0.0:9000

@zacronos
Copy link

zacronos commented May 6, 2015

@zeeshanjan82, then in that case gulp is acting as your backend server. I haven't used gulp that way, so I don't know what you need to do. But, since you will eventually have a real backend, anything you do now with gulp is just going to be a temporary fix.

I would recommend that you ignore the problem for now, and revisit when you have started to build your backend. Or, you could go ahead and create a skeleton backend so you can fix this problem the "right" way instead of a temporary fix via gulp.

@zeeshanjan82
Copy link

thanks @zacronos I will surely follow your advice and will get back when I have implemented the backend.

@marcandrews
Copy link

Are you using any sort of authentication and then checking for authorization on $stateChange* in a run block?

Sorry for the necro and if my terminology is incorrect; I'm new to AngularJS.

@gopikrishnahm
Copy link

@bikashsharmabks: Where do you add this code to avoid browser refresh taking to home page.

angular.module('app').run(['$state', '$stateParams',
function($state, $stateParams) {
//this solves page refresh and getting back to state
}]);

@horiaIon
Copy link

horiaIon commented Sep 4, 2016

@jonathanadler

I have the same problem when i refresh my page manually, and it's caused because of the resolve function from my state (i load some data from server). Did you managed to go pass this issue, without timeout?
Can you provide some code example?

Thanks,
Horia.

@lifemixture
Copy link

gopikrishnahm, thank U very much good man!
I spent week avoiding browser refreshing taking to home page.

@chetanganguly
Copy link

**@lifemixture @gopikrishnahm **
where we can we this code ..

angular.module('app').run(['$state', '$stateParams',
function($state, $stateParams) {
//this solves page refresh and getting back to state
}]);

i tried to add but still its going to home page ..can you have any sample..?
please reply ASAP

here is my config
_BaseModule.config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('', '/login');
$urlRouterProvider.otherwise('/notfound');
$stateProvider
.state("login", {
url: '/login'
, templateUrl: "Login/login.html",
controller: "LoginController",
controllerAs: "ctrl",
title: 'Login',
authenticate: false

        })
        .state("default", {
            url: '/default',
            templateUrl: "Login/login.html",
        })
        .state("home.abcd", {
            url: '/AccountsList',
            templateUrl: "abcd/abcd.html",
            controller: "abcdController",
            controllerAs: "ctrl",
            title: 'abcd',
            authenticate: true
        })

}]);_

@lifemixture
Copy link

lifemixture commented Jul 25, 2017

Hi @chetanganguly. I really stuck with this issue about half a year ago.
Injecting '$state' and '$stateParams' to run section helped me, I do not understand why. Than I removed them from run section and it was still working (like a magic).
Also do not forget to add 'base' tag to your main html.

Maybe this will help you
https://github.com/lifemixture/my-data-store/blob/master/public/js/app.run.js

@padhyakash
Copy link

@lifemixture

this worked for me on local machine but not on server, Any hint please?

$rootScope.$on('$stateChangeStart', function (event, toState) {
if (!$rootScope.global.loggedIn && (restricted.indexOf(toState.name.split('.')[0]) !== -1)) {
//console.log("restricted");
event.preventDefault();
$state.go('login');
}
if (toState.name === 'login' && $rootScope.global.loggedIn) {
event.preventDefault();
$state.go('home');
}
});

@Husnainsheikh84
Copy link

angular.module('app').run(['$state', '$stateParams',
    function($state, $stateParams) {
        //this solves page refresh and getting back to state
}]);

This will solve the issue

Thanks , It worked for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests