$state.reload() should reinitialize the controller #582

Closed
ghengeveld opened this Issue Nov 14, 2013 · 170 comments

Comments

Projects
None yet

As discussed in #76, $state.reload() does reload the resolves, but doesn't reinitialize the controller with the newly resolved values. Since the whole point of reloading the resolves is to refresh the scope with the new data, reinitializing the controller is a requirement for $state.reload() to be of any use.

Demo: http://plnkr.co/edit/GNr1bN?p=preview

mfield commented Nov 14, 2013

I don't know whether this behavior is intentional or not. In my application, I skirted this issue by setting a $watch on the values in $state like http://plnkr.co/edit/DVFG8T?p=preview

Good to see there is a workaround. Still, it does make sense to reload the controller too so it resets it's state. Besides, using $state.$current.locals.globals circumvents the DI syntax for resolved properties, which makes it a lot less explicit (and explicit DI is what makes it so nice and simple).

I haven't checked but if reload induces stateChangeSuccess then that would be better than watching if you're watching just so you can track reload-based changes.

👍

panga commented Dec 2, 2013

I agree with @ghengeveld, $state.reload() also should reinitialize the controllers to refresh scope.

Member

nateabele commented Dec 2, 2013

Yup, agreed, sorry for overlooking that. It'll get fixed as soon as I have time.

👍

👍 Anyone know another workaround for this? I'm building out a massive SPA and I need each of the controllers (all different routes) to refresh when the user changes a drop down that is part of the surrounding chrome of the SPA. Right now it looks like I have to write a bunch of code in each controller which is going to be bad. Thanks!

Have you tried flipping the reload flag on transitionTo?

        $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true });

Thanks for the thought. I gave it a shot but to no avail...

I even tried changing:

  function shouldTriggerReload(to, from, locals, options) {
    if ( to === from && ((locals === from.locals) || (to.self.reloadOnSearch === false)) ) {
      return true;
    }
  }

To:

function shouldTriggerReload(to, from, locals, options) {

    if(options.reload) {
        return true;
    }

    if ( to === from && ((locals === from.locals) || (to.self.reloadOnSearch === false)) ) {
      return true;
    }
  }

Because it was returning false when options.reload == true (which didn't make sense to me) but that didn't work either. Bummer! I'm gonna have to put watches on a broadcast for that "global drop down change" I guess until this is resolved or I can figure it out on my own time. UI Router is AMAZING otherwise though. I recommend it over the built in Angular one whenever I talk or present on Angular!

zakjan commented Jan 28, 2014

What is state of this bug?

Member

nateabele commented Jan 28, 2014

@zakjan Hope to have a fix pushed by this weekend.

👍 Sweet, pumped for this as it should clean up the code on a few of my pages quite significantly. Thanks!

zakjan commented Jan 31, 2014

👍 looking forward to it

sausaw commented Feb 4, 2014

👍

@nateabele any updates?

I'm using some transition state as a workaround:

state('transition', {
  url: 'transition?destination',
  controller: function ($state, $stateParams) {
    $state.go($stateParams.destination);
  }
})

And then:

//state won't reload
$state.go('new-state');
//temporary workaround to ensure reload
$state.go('transition', {destination: 'new-state'});

@PeterMajer great hack, i was using

$state.transitionTo('new-state', null, {'reload':true});

zakjan commented Feb 13, 2014

Any of those workarounds don't reinitialize controller for me.

one workaround is recreate the view by toggling the value of ng-if provided u have the controller defined inside the ng-if div or on it

zakjan commented Feb 20, 2014

Thanks! Here is complete working solution, for now.

<div ng-if="!hideContent">
  <div ui-view></div>
</div>
$scope.reload = ->
  $state.transitionTo($state.current, $stateParams, reload: true).then ->
    $scope.hideContent = true
    $timeout ->
      $scope.hideContent = false
    , 1

koganei commented Feb 20, 2014

👍 zakjan

👍 zakjan

Thanks a lot, @zakjan and @rohitranjan1991 ! It works for me too.

malixsys commented Mar 6, 2014

This works for me now:

            var current = $state.current;
            var params = angular.copy($stateParams);
            $state.transitionTo(current, params, { reload: true, inherit: true, notify: true });

for those who don't use coffeescript, zakjans solution in normal js:

$scope.reload = function() {
  return $state.transitionTo($state.current, $stateParams, {
    reload: true
  }).then(function() {
    $scope.hideContent = true;
    return $timeout(function() {
      return $scope.hideContent = false;
    }, 1);
  });
};

hello all... i wanted to see if there are any plans to fix this issue... i basically need the controller to run upon refresh so that i can update the scope... thank you

Member

nateabele commented Mar 15, 2014

[I] wanted to see if there are any plans to fix this issue.

@giancarloa Yes.

great... thank you nateabele... perhaps i should have been more specific... is there any timetable whatsoever of when this will be fixed? our organization is still on 0.0.1 but we plan on making the jump soon... this is something we've been wanting for a while... thanks again

@giancarloa Did you try:

$state.transitionTo($state.current, angular.copy($stateParams), { reload: true, inherit: true, notify: true });

What does it do for you?

hi there @malixsys ... as i mentioned above, we're still on 0.0.1... so we not have not tried this yet... but unless i am misunderstanding this issue, it appears that when the current state is "reloaded", the state's controller function does not run again... is this a correct understanding of the issues??? we plan on jumping soon to the latest version of ui-router regardless of whether this gets fixed but it would be great to know a rough idea of when a fix will be available... thanks again

I was having the issue with controllers not reloading, but this seems to reload and re-resolve the resolves:

ui-sref="dashboard" ui-sref-opts="{reload: true}"

Awesome. Thanks @malixsys!

I just tweaked my source code since it sounds like @nateabele has an official fix coming in soon. @nateabele does this look right? If so maybe just pull it in and be done with it to save you some extra effort? I tested this locally on routes with and without stateParams and it seems to work fine but perhaps I'm missing a more complicated situation...

Change (in the source):

$state.reload = function reload() {
    $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: false });
};

To:

$state.reload = function reload() {
    $state.transitionTo($state.current, $stateParams, { reload: true, inherit: true, notify: true });
};

sadlerw commented Mar 27, 2014

👍 johnculviner

@johnculviner That solution worked for me, but only from 0.2.10 (didn't work in 0.2.8).

Member

nateabele commented Mar 27, 2014

@johnculviner Interesting. I'll give it a go when I have some spare time. Thanks for investigating.

@johnculviner awesome workaround. 👍

@timkindberg wondering if anyone is starting a pull / currently working on this? :)

Any timeline on an official fix? Don't want to deal with workarounds if it will be fixed soon.

I agree with @kevinrenskers, will be great when a fix for this is completed.

I tried the @malixsys / @johnculviner workaround on 0.2.10 and it doesn't work for me -- shouldTriggerReload always returns true, so we bail out early. (I'm confused about the name/purpose/logic of shouldTriggerReload -- given the logic, it seems to me the name should be shouldSkipReload. The logic is: "if going to the state we're already in, and the locals are the same or we don't care if they're different, return true".)

It also seems to me that in shouldTriggerReload, the options.reload case should trump the self.reloadOnSearch === false case, that is, even if reloadOnSearch is false, options.reload should override it.

I should mention my use case is: I use ui-router with reloadOnSearch: false and manipulate the query string myself and add my own watches to handle it changing where necessary, but I have one case where it's too hard to handle all the necessary changes directly, and I'd rather just reboot the controller. That is, I generally want the reloadOnSearch: false behavior but I was trying to use $state.reload() to opt into the normal reloadOnSearch: true behavior in one specific case, and that's how I ran into this bug.

weierophinney referenced this issue in zfcampus/zf-apigility-admin May 7, 2014

Closed

First new service disappears from the list after creation #159

@metamatt Don't get confused by the shouldTriggerReload, I think that was an internal use-case...

My resolves get called again in 0.2.10 just fine...See the plunkr below after you click Save in Profile:

http://plnkr.co/edit/ybA9UL?p=preview

I still have the issue "bug with controllers reinstantiating right now, fixing soon". When is "soon"? @nateabele

Sonium commented Jun 11, 2014

Turns out that for some of my cases, just doing a vanilla javascript location.reload() (equivalent to manually refreshing in your browser) did exactly what I wanted. I don't think it preserves non-query state params, but that might be enough for some cases.

👍 For Fix :-)

This issue is killing me.

I don't see how... There are easy workarounds...

@malixsys Is the recommended way to just change the source code as per @johnculviner suggestion for the time being, instead of duplicating code in every controller ?

$state.reload = function reload() {
    $state.transitionTo($state.current, $stateParams, { reload: true, inherit: true, notify: true });
};

yes the code is easy however i keep having issues with reloading nested states in general.. i dont understand either why thats the case but it is

On Jun 12, 2014, at 10:25 PM, M Alix notifications@github.com wrote:

I don't see how... There are easy workarounds...


Reply to this email directly or view it on GitHub.

stryju commented Jun 26, 2014

one way to approach it, would be:

// ...
.state('parent', {
  url        : 'parent',
  controller : function ($scope, $rootScope) {
    var off = $rootScope.$on('$stateChangeSuccess', function () {
      if ($state.includes('**.parent')) {
        // update your resources here, do whatever you need
      }
    });
    $scope.$on('$destroy', off);
  }
})
.state('parent.child', {
  url : 'child',
});

pros:

  • you specify what is being refreshed
  • you update only what you need, via the controller (no need to "reinitialize")

cons:

  • you need to specify what is being refreshed
  • a lot of code repetition

this solution has an edge case in which it could create a conflict:

if the child state and parent have the same name, like:
users and users.edit.team.users

but that could be avoided with more strict state comparison :-)

The override to $state.reload() doesn't work for me. v0.2.10.

angular v.1.2.19

It's never going to work. Get over it.

peruzzo commented Jul 10, 2014

+1

@johnculviner are you using resolves in your parent state? That change to the source still isn't working for me. :(

👍

+1 for this fix

👍

👍 srsly

here's a little snippet I use as a workaround:

app.config(function($provide) {
  $provide.decorator('$state', function($delegate) {
    $delegate.reinit = function() {
      this.transitionTo(this.current, this.$current.params, { reload: true, inherit: true, notify: true });
    };
    return $delegate;
  });
});

and then just call $state.reinit() whenever you need to reload the route and reinitialize controller

soyuka commented Jul 29, 2014

Thanks @rawry this is a perfect fix.

This is still weird because the api docs says:

reload() is just an alias for:

 $state.transitionTo($state.current, $stateParams, { 
  reload: true, inherit: false, notify: false 
});

Should options not be replaced to notify again? We do want to reload!

@rawry, this still doesn't work for me. Nothing works. Time to throw my computer out the window.

Where are you putting this code, because maybe I'm doing it wrong? For example, I do a request to my server, add some data, and then $state.go('parentState'). I have a resolve that is SUPPOSED to refresh the data, but doesn't.

soyuka commented Jul 29, 2014

I'm doing like this instead of using $state.reload():

angular.controller('myCtrl', function($state) {
//when user did some action, load some http REST and call:
      $state.transitionTo($state.current, $state.$current.params, { reload: true, inherit: true, notify: true });
});

I am resetting the current state, you might want to call the ^ state or check that $state has a $parent sibling or something like that (not tested).

Contributor

gustavohenke commented Aug 4, 2014

So, it's been almost 9 months since this issue has been opened, and looks like there's no official fix yet.

Dear maintainers, we all know that this is open source and we could simply have forked and patched the fix, but it's sometimes easier if you guys could take a look for a few minutes and find the reason of the bug. You're familiarized with the code and the tests!
For a new contributor, sometimes it's not so easy to get started.

malixsys commented Aug 4, 2014

@gustavohenke if someone explains what does not work for them, starting with this plunker, I will make a PR to fix it...

http://plnkr.co/edit/ybA9UL?p=preview

Contributor

gustavohenke commented Aug 4, 2014

The problem is in the notify option - when it's false, things stop working.

malixsys commented Aug 4, 2014

I see. That has not proven to be a problem in my usage of ui-router...
If I know things will have changed on the server, or I just want my resolves to reload, I just use $state.transitionTo($state.current, $state.$current.params, { reload: true, inherit: true, notify: true });

br0th3r commented Aug 4, 2014

I use the same than @malixsys and it works like a charm. I am using that straight in my code.

soyuka commented Aug 4, 2014

same here

EDIT: Nevermind, this works for transitioning to anothe rstate:

$state.transitionTo('settings.locations', $state.$current.params, { 
  reload: true, inherit: true, notify: true 
});

arsfeld commented Aug 4, 2014

Indeed when notify is set to false in transitionTo it doesn't work, but why would you set that? Why can't reload be aliased to $state.transitionTo($state.current, $state.$current.params, { reload: true, inherit: true, notify: true });?
The current behaviour for reload is just frustating.

soyuka commented Aug 5, 2014

I think that reload sould indeed be changed to the same behavior then this.

swlasse commented Sep 2, 2014

$state.transitionTo($state.current, $state.$current.params, { reload: true, inherit: true, notify: true }); ... works fine - thanks for the workaround.

I have written some sort of url manager which catches a 'redirect' state. From this state, depending on the content of the stateparameters, the code should redirect to a specific childstate. The transition to works fine, but the reload option doesn't seem to work. The controller of the child state does not get called.

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
            // Check if the targeted state is the redirection state
            if(toState.name == 'myapp.redirect'){
                var gotoState = urlManagerService.getState(toParams);
                $state.transitionTo(gotoState.state,toParams, { location:false, inherit:true, reload:true, notify:true });
            }
        });

The resolve function of that state however does get called.
Is there still a bug in this or am I doing something completely wrong?

@ghost

ghost commented Sep 10, 2014

Here's a shorter version
$state.go('.', null, { reload: true });
of
$state.transitionTo($state.current, $state.$current.params, { reload: true, inherit: true, notify: true });

graffic commented Sep 15, 2014

@esditm The shorter version works really well 👍

smajl commented Sep 15, 2014

I am also using $state.go($state.current.name, $state.params, { reload: true }); instead of $state.reload();. Works well.

I've added a TimeStamp to my TemplateUrl function, so now it reloads correctly the state re-firing everything:

templateUrl: function ($stateParams) {
return '/l3/templates/pages/edit/' + $stateParams.id + '?' + new Date().getTime();
}

In Fiddler I can see a call to this:
/templates/pages/edit/1015?1410873932300

stryju commented Sep 16, 2014

@BrunoShortcutTo701 that's not really a good practice, esp. when you either want to cache the templates OR don't want to use external template at all :-)

@stryju Yes I know,but it is a good solution if we cannot figure out how to solve this bug, expecially in my case whre the SPA application is for a CMS platform where less templates are cached, the better is!

stryju commented Sep 16, 2014

@BrunoShortcutTo701 i thought it was solved with $state.go( ..., { reload : true });?

I am in the same boat as @metamatt . For my normal navigation on a certain state I have reloadOnSearch:false because I dont want to rerun the controller when going between some slides (and manually updating the url page=2), but in the case the user clicks refresh action I want to force a reload of the controller, in this case none of these solutions work. They do work on other state definitions when reloadOnSearch:true but it seems the reloadOnSearch:false case is trumping all of these solutions. I would think that $state.reload() should truly force a reload regardless of reloadOnSearch

metamatt commented Oct 1, 2014

Like I said before, I think both the name and behavior of shouldTriggerReload are wrong (to the extent I'm understanding it; stop me if I'm wrong). @malixsys I know it's an internal function only, so the name doesn't really matter and nobody outside can call it; but it interferes with the handling of the reloadOnSearch:false case that I and @travisdahl are using.

I think shouldTriggerReload would better be named shouldSkipReload, and the options.reload check should be hoisted farther out so it overrides reloadOnSearch -- right now, if I set reloadOnSearch:false for a state, then shouldTriggerReload will always return true (for a transition from that state to itself with the same locals, but even when options.reload is true).

Proposal: change

  function shouldTriggerReload(to, from, locals, options) {
    if ( to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false)) ) {
      return true;
    }

to

  function shouldSkipReload(to, from, locals, options) {
    if ( !options.reload && to === from && (locals === from.locals || to.self.reloadOnSearch === false) ) {
      return true;
    }

The logic is: short-circuit the reload if

  • reload was not explicitly requested
  • and the to state is the from state
  • and the locals did not change, or they did change but the state was defined with reloadOnSearch: false

I see @johnculviner already proposed basically this, too.

I suppose I should just dump this in a PR instead. Which wouldn't fix the originally reported variant of this problem #582, but would enable the @malixsys / @johnculviner workaround to work even for the reloadOnSearch: false case.

(Now that there are ui-router releases happening -- I see 0.2.11 happened recently, and presumably with AngularJS 1.3 imminent there will be more -- is there a plan to fix this bug #582, too? Either via #582 (comment) or some other way?)

👍 for the work around

I had the same issue but triggered an infinite loop. so my work around:

I'm having root state for the app as abstract which resolves calls async function and processes data (say X) and according to X the template of the child state of root is rendered in the templateProvider. The logic of re rendering the template is :

  1. resolve the data X in root and send it to the controller
  2. if the X satisfies the condition call $state.reload()(the above one)

now this triggers infinite loop in my app.
so the workaround for now is to store a value in sessionStorage which will guide the execution of $state.reload().

Is there a better way of doing it?

seiyria referenced this issue in IdleLands/IdleLandsOld Oct 10, 2014

Closed

web enhancements, round 3 #251

noducks commented Oct 13, 2014

+1 for fix

mkamayd commented Oct 22, 2014

+1

Hi all, what's the current status on this issue?

The current state is that you need to use one of the workarounds mentioned above.

To give some context on the original bug, if i have a button that triggers a reload, it will actually reload on the second click...

+1 this needs to get fixed

christopherthielen self-assigned this Oct 28, 2014

christopherthielen added this to the 0.2.12 milestone Oct 28, 2014

+1 This definitely needs to be fixed. Using the $state.transitionTo( $state.current, angular.copy($stateParams), { reload: true, inherit: true, notify: true } ); workaround but want an official solution.

on last day i am facing the same issue, and got a solution, may be its work for you,

in .run i added an statechange event, and inside it i clear cache of ionic, please try this code

app.run(function($ionicPlatform, $rootScope, $ionicHistory) {
   $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
      $ionicHistory.clearCache();
   });
});

okonon commented Dec 31, 2014

The @srehanuddin solution worked for me!!!

You should probably not do that on EVERY $stateChangeStart... Maybe set a flag when you know you want to reload?

okonon commented Jan 2, 2015

Actually I soved differently: basically I fetch data $ionView.loaded lifecycle event

hpawe01 commented Jan 5, 2015

If you are using the current ionicframework (ionic: v1.0.0-beta.14, angularjs: v1.3.6, angular-ui-router: v0.2.13), the problem with the not-reloading-controller could be caused by the new caching-system of ionic:

Note that because we are caching these views, we aren’t destroying scopes. Instead, scopes are being disconnected from the watch cycle. Because scopes are not being destroyed and recreated, controllers are not loading again on a subsequent viewing.

There are several ways to disable caching. To disable it only for a single state, just add cache: false to the state definition.

This fixed the problem for me (after hours of reading, trying, frustration).

For all others not using ionicframework and still facing this problem: good luck!

Thank you very much for this post hpawe01, I lost quite a few hours due to this new feature and cache: false worked perfectly!

malixsys commented Jan 7, 2015

@hpawe01 Indeed! +1

$stateProvider.
  state('home', {
    url: '/',
    cache: false,

oozzal commented Jan 11, 2015

Thanks @hpawe01. Certainly saved me few hours. 🕙

+1 for an official fix please.

The proposed milestone of this issue (at the time of writing) is 0.2.12 and the current release version of ui-router is 0.2.13. Is the issue likely to be fixed anytime soon? If so, when roughly?

ui-router is amazing! But this issue has been open for over a year...

Contributor

christopherthielen commented Jan 13, 2015

This issue was closed 2 months ago

Oh, my apologies, I assumed it needed re-opening due to the posts from a few days ago.

Thanks for the fix :)

thanks @hpawe01 - you saved my day!

pholly commented Jan 15, 2015

I see that this issue was closed 2 months ago and included in the 0.2.12 release: 7344342

Does anyone know if this fix works even when reloadOnSearch=false is defined for the state? Based on the comments of @metamatt in #582 (comment) and @travisdahl in #582 (comment) even if notify is set to true the controller will not get reinstantiated if reloadOnSearch is false.

using ionic framework Thanks @hpawe01 for the fix !

dhautot commented Jan 31, 2015

+1 @hpawe01
thanks !

@hpawe01 thank!

brunodb3 commented Feb 4, 2015

@hpawe01 Awesome fix!! Thank you very much!

@hpawe01 Thank you! This problem spend me few hours .

$stateProvider.
state('some', {
url: '/some',
cache: false,

@hpawe01 thank you!

Can someone tell me if my issue is what is being addressed here?

my default starting state is tied to a controller. (after first install and run of app) this controller draws a map (and does other things). If, while getting data for the map i see there is no internet connection; i simply display a msg stating "no internet" and i return out of the controller (which leaves msg stuck on the screen and app basically stalled).

the goal is to RERUN the controller after the user goes to his settings and enabled his wifi.

i have added in .run an on resume watch: $ionicPlatform.on('resume', function(){}) and tried dozens of possible methods of rerunning my default controller including everything mentioned in this post and other posts.

  • $state.reload()
  • $state.go()
  • $state.transitionTo($state.current, $state.$current.params, {reload: true, inherit: false, notify: true});
  • disabling cache for this state
  • adding a broadcast in .run and then watching for it in controller

and many version of all of these.

I can get transtionTo code hit in many different ways; and it returns with $state.current but the first line of my controller is never hit again. and, of course, no errors.

as usual with angular, burned up a day with what should be 2 lines of trivial code... any hints on how to FORCE a page load?

oscar-b referenced this issue in Narzerus/angular-permission Feb 13, 2015

Closed

Bump angular-ui-router dependecy to latest available #42

Ok honestly this is still broken. And none of these workarounds worked at all. I tried all of the following:

$state.reload();
$state.go($state.current, {}, { reload: true  });
$state.transitionTo($state.current, $stateParams, {  reload: true, inherit: false, notify: false  });
$state.transitionTo($state.current, $stateParams, {  reload: true, inherit: false, notify: true  });
$state.transitionTo($state.current, {}, {  reload: true, inherit: false, notify: false  });
$state.transitionTo($state.current, angular.copy($stateParams), {  reload: true, inherit: false, notify: false  });

The only thing that has worked to fully reload the route AND controller, is creating a dummy param and setting it randomly. Enjoy:

$state.transitionTo( $state.current, {reload : Math.random()}, { reload: true, inherit: true, notify: true } );
Contributor

christopherthielen commented Feb 20, 2015

If it's still broken , provide a plunk demonstrating the issue.

Come on! Still?

This works perfectly for me in my Alert device:
reload: function() {
var current = $state.current;
var params = angular.copy($stateParams);
$rootScope.$emit('reloading');
return $state.transitionTo(current, params, { reload: true, inherit: true, notify: true });
},

sunild commented Feb 20, 2015

This is the issue that keeps on giving! Sorry for the useless comment, but after a year of following this thread I had to say something before I unsubscribed. This is a great, indispensable project, thank you!

wilk commented Feb 21, 2015

+1 @hpawe01!
thanks!

@hpawe01

thank you man!!! after hours of looking into this i finally stumbled upon your comment... saved me of more hours of looking into this!

amazing, thanks :)

.state('srtypelist', {
url: '/list',
templateUrl: 'templates/tab-srtypelist.html',
controller: 'srTypeListCtrl',
cache: false // force reload the controller every time
})

maurei commented Mar 10, 2015

Hi,

I've been following this thread for a couple of days now. I've been trying to force a controller re-initialization on a ui-sref trigger, which works by doing cache: false

However, the reason I want to re-initialise my controller is because of some ajax request in the resolve function that precedes this initialization.

The issue I'm facing is that the resolve function won't be re-executed at all when using cache: false. Can anyone help me out on this?

Cheers

This thread is 16 months long :)

Do you reload and how?

This works for me:

function reload() {
    var current = $state.current;
    var params = angular.copy($stateParams);
    return $state.transitionTo(current, params, { reload: true, inherit: true, notify: true });
}

and calls my resolve:[] again

@malixsys This does not work for me. Its incredible this is still an issue. I've tried both go and transition

@geemang2000 can you reproduce in a plunkr/jsfiddle/gist?

May bad.. this working. Have an asynch issue. I'm updating a record and then going to a list page. The list page loads it data before the update finishes...

Use promises!

    Service.update().then(function(){reload();});

Martin Alix
+1 514 515-3469
sent via mobile

On Thu, Mar 12, 2015 at 4:10 PM, geemang2000 notifications@github.com
wrote:

May bad.. this working. Have an asynch issue. I'm updating a record and then going to a list page. The list page loads it data before the update finishes...

Reply to this email directly or view it on GitHub:
#582 (comment)

thanks @malixsys . yep promise fixed my issues. BTW: my resolves are working wtihout any reload etc. Plus I'm using go instead of transitionTo

still having an issue with this. my resolve does get executed again but since the controller doesn't initialize my resolve variable never gets re assigned back to my scope. am i doing something wrong here because I keep seeing people saying they got this to work!?!?

state:

  .state('tab.locations', {
    url: '/locations',
    views: {
      'tab-locations': {
        templateUrl: 'templates/tabs/tab-locations.html',
        controller: 'LocationsCtrl'
      }
    },
    resolve: {
      locationResource: 'Location',
      locations: function(locationResource, $stateParams){
        return locationResource.query().$promise;
      }
    }
  })

controller:

  .controller('LocationsCtrl', ['$scope', 'locations', '$state', function($scope, locations, $state) {

   $scope.locations = {};

   $scope.locations = locations.data; //never gets reassigned resolve data after reload because it is not initializing or am i missing something?

}]);

reload snippet I am using:

$state.transitionTo('tab.locations', $state.$current.params, { 
  reload: true, inherit: true, notify: true 
});

One of these days I'm going to find some time and fix this. And the UI Router Gods will smile. And a child will be born. And this thread will be forever silent...

@dshefchik prophet on the holy lands of Angular, splitting the waters of $stateprovider to guide the people toward reloaded controllers...

Joking aside, Ionic FW and it's cache handling was the problem for me too, so after a hour going through this interminable thread I wanted to throw in a BIG thank to @hpawe01 for his revelatory post!

Was having same issue despite setting reload: true in latest version .. @hpawe01's solution worked for me ( setting cache to false in ui-router state settings )

I am using Ionic and almost every, if not all of my views are being populated with API data. I want to the ui-router refresh to work, but will turning off caching on all of my states cause performance issues?

@hpawe01's solution works for me!!

This doesn't seem to be working in IE 11 for me (it does work in chrome and FF).
In Chrome and FF, it does seem to reload all controllers and states (including parents). Reading the thread, shouldn't $state.reload() only reload the current state and its children?

@masterkidan I'm seeing the same result. Working for Chrome/FF, but not IE11. If I get a chance I'll create a plunker show the issue.

@hpawe01 - 👍 Thanks!

I'm trying ui-router 0.2.14 and am noting yet another way that shouldTriggerReload breaks this behavior. If I set reloadOnSearch: false for a state, then change a $stateParam that's part of the URL path (not a search param), I don't see the controller get reloaded. If I trace through the code, it's shouldTriggerReload returning true (which, again, counterintuitively means "skip reload") that causes the problem.

This falls directly out of the coded behavior for shouldTriggerReload:

  function shouldTriggerReload(to, from, locals, options) {
    if (to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false))) {
      return true;
    }
  }

That final "or" clause means that for a state with reloadOnSearch: false, the locals check doesn't matter. If you transition to the same state you're already in (to === from) and that state has reloadOnSearch: false, you won't get a reload, no matter how different the state params are.

My take -- stop me if I'm wrong -- is this makes reloadOnSearch: false pretty much unusable. I maintain that it should be called shouldSkipReload and the reloadOnSearch === false condition should be applied more locally, though my previous suggestion was incomplete; it doesn't distinguish between path params and search params.

So we want something more like

  function shouldSkipReload(to, from, locals, options) {
    if ( !options.reload && to === from && (locals === from.locals || (to.self.reloadOnSearch === false && localsDifferOnlyInSearchParams(locals, from.locals)) ) {
      return true;
    }

with a suitable definition of localsDifferOnlyInSearchParams.

The reason I haven't just send this as a PR is I suspect there are subtleties I'm missing; I think in terms of URLs instead of states and maybe there are additional wrinkles for states that aren't expressible via URLs, and there are probably other reasons nobody's changed this in years. But please consider that the current behavior of reloadOnSearch: false is broken -- it breaks the reload flag, it breaks changes to non-search params.

Ah, this last thing I'm complaining about is already filed separately as #1079.

@metamatt metamatt pushed a commit to metamatt/ui-router that referenced this issue May 18, 2015

Matt Ginzton fix($state): reloadOnSearch should not affect non-search param changes.
The handling of `reloadOnSearch: false` caused ui-router to avoid
reloading the state in more cases than it should. The designed and
documented behavior of this flag is to avoid state reload when the
URL search string changes. It was also avoiding state reload when
the URL path (or any non-search parameters to the state) changed,
and even when state reload was explicitly requested.

This change

- flips the name of shouldTriggerReload (and the accompanying guard
  boolean, skipTriggerReloadCheck) to match the direction of the
  logic: shouldSkipReload and allowSkipReloadCheck

- teaches shouldSkipReload to look at the types of the differing
  parameters, and only skip the reload if the only parameters that
  differ were search parameters

- pulls the test for options.reload to the front of the complex
  boolean expression. (I think calling $state.reload() explicitly
  should reload a state even if it has reloadOnSearch:false. But I
  don't understand exactly why the test for this was where it was, and
  maybe there's a good reason I'm missing. Also, if the behavior I
  favor is deemed correct, we could also achieve that by setting
  allowSkipReloadCheck=false for all truthy values of options.reload,
  namely, if options.reload===true, and then shouldSkipReload wouldn't
  even need to look at options. I left a comment about this in the
  source too and would appreciate feedback.)

Fixes #1079. Helps with one of the cases broken in #582.
49ec726

jorisw commented Jun 3, 2015

To anyone arriving here googling for re-execution of an ionic framework controller when using state.go():

If you want some code in your controller to execute every time its state is arrived at (not just the first time), wrap it in a beforeEnter (before the transition) or enter (after the transition finishes) event listener for that state:

.controller('yourCtrl', function($scope, $rootScope, $other, $depencies) {

    $scope.$on('$ionicView.beforeEnter', 
                       function() {
                               // Code here is always executed when entering this state
                       }
    );

});

zodiake commented Jun 9, 2015

thanks @jorisw !

Thanks @hpawe01
It saved me a lot of time..!

gakuba commented Jun 13, 2015

Thx @malixsys. the cache:false fixed my problems.

Cheers.

Setting a cache worked fine for refreshing scope for me. Wondering how that will effect the preformance since data is not cached on a route now.

Was there an official fix for this ?

Contributor

christopherthielen commented Jun 16, 2015

@novarac23 officially this has been fixed for some time... Most of the recent comments are related to ionic framework, not ui router.

👍

@hpawe01 's solution doesn't work for me 😢

Should we use location.replace(location.pathname); ?

ComeOutToPlay referenced this issue in Narzerus/angular-permission Jul 15, 2015

Closed

Caching of roles #36

Why not use trivial this fix:

<a href="javascript:history.go(0)">Reload this page</a>

First off, apologies, I know this is closed, but I cannot get my controller to re-initialise. I have tried everything that has been mentioned in this ticket and am at my wits end trying to get it working

I have a state that uses a resolve to resolve some data from a resource. I then pass it through to the controller. On initial entry of the state, my resolve is executed and my controller gets the resolved param injected into it, which is as expected. The state displays a view that is a list of orders in a cart.Each row in the list can be deleted and upon deletion, I would like to reload the page to show the updated list.

When i do this, my resolve gets executed, the service that houses the resource gets executed, but it seems that the result is not injected into the controller as expected

@bautistaaa, did you ever manage to get a solution to your problem? I have the exact same problem, and your code is pretty much identical to mine.

I am using the following versions
AngularJS v1.2.28
Angular UI Router v0.2.13

var app = angular.module("orders-app", ['ngResource', 'ui.router', 'datatables', 'ui.bootstrap', 'ngAnimate', 'ngCookies', 'pascalprecht.translate']);

app.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('orders', {
            url: '/orders',
            templateUrl: 'angular_modules/orders/views/orders.html'
        })
        .state('orders.detail', {
            url: '/detail',
            templateUrl: 'angular_modules/orders/views/order-details.html',
            resolve: {
                userMetaData: function(userMetadataService){
                    return userMetadataService.getUserMetaData().$promise;
                }
            },
            controller: 'orderDetailsController'
        });
    $urlRouterProvider.otherwise('/orders/detail');

});

app.controller('orderDetailsController', function($rootScope, $scope, $state, $stateParams, $resource, DTOptionsBuilder, DTColumnDefBuilder, ordersService, userMetaData) {

    $scope.model = $scope.model || {};

    $scope.model.userMetaData = userMetaData;

    $scope.model.orderdetails = $scope.model.orderdetails || [];

    $scope.getOrderDetails = function(){
        return ordersService.getCurrentOrderDetails().query({ type: 'current', org: $scope.model.userMetaData.orgId, user: $scope.model.userMetaData.id});
    };

    $scope.getOrderDetails().$promise.then(
        function(data){ 
            $scope.model.orderdetails=data;
        }, 
        function(error){ 
            $scope.errormsg = "error"; 
            alert('error');
        }   
    );

    var errorCallback = function (e) {
        alert('Something went wrong '+e.data.Message);
    };

    var deleteSuccessCallback = function (e, cb) {
        $state.go($state.current, {}, {reload: true, inherit: true, notify: true});
    };

    $scope.deleteOrder = function (row) {
        ordersService.getOrderResource().remove({ id: row.id}, deleteSuccessCallback, errorCallback);
    };

});

@brianmyler Plunker or it never happened :)

@malixsys, you are correct, I should have provided a plunker, in fact, if i had of in the first place, I would have found that my issue was in fact nothing to do with the re-initialisation of my controller.

Turns out the problem was in fact my own stupidity :-). Ther service factory that housed the resource object that gets the user data from a rest endpoint was(well i thought it was) caching the response on the first call to this service. Turns out I had a typo and was in fact caching an empty object, which is why i had the problems 2nd time around.

Anyway, apologies for wasting your time, plunkers first next time :-0

@brianmyler No worries! I meant it in jest, but plunkers DO make it easier to diagnose and help.
I am just amazed at this closed issue's longevity, though!

kszpirak commented Aug 1, 2015

Super stupid problem. CACHE parameter solves the problem for me...

.state('test.index', {
url: '',
templateUrl: dir + '/test/index.html',
controller: ctrl + 'List',
cache: false,
resolve: {
service: "ListService",
resloveData: function(service, $stateParams) {
return service.get({
listType: 'test'
})
}
}
})

For the people using Ionic. You can disable the cache per view by adding cache-view="false" to the

cache:false in the state definition or $state.go with reload parameter didn't help when using the Ionic framework.

Thanks mgamsjager, doing this in Ionic worked for me:

< ion-view view-title="Locations" cache-view="false" >

NaomiN commented Sep 22, 2015

So, what is the current status of this problem and what is the exact fix I need to implement? This is my current code:
if ($scope.searchParameters.categoryId != 0) {
window.console && console.log('Going to category state...')
$state.go('category', { categoryId: $scope.searchParameters.categoryId, createDaily: createDaily },{ reload: true });
}

How should I change it to cause the Init of the controller that is associated with that state to fire?

Thanks in advance.

NaomiN commented Sep 22, 2015

This is a very long thread and I am not sure what is exactly solution for my problem. On my index page I have two buttons Create Daily and New. Both of them correspond to the same state and should transition to the same view, but I need a server call to get updated model. I found that init of my second controller associated with that view is not firing after I added a new, clicked Add button to save and then clicked on the Create Daily on the index page. I've added cache: false without any effect. I'm using Google Chrome and AngularJS v1.3.13 for Angular.js and State-based routing for AngularJS

  • @Version v0.2.8 for ui-router.js. What should be my solution to make sure my API call is happening when I press New/Save then CreateDaily buttons (or other way around)?

NaomiN commented Sep 24, 2015

What is the official version of ui-router.js? Nuget only offers 0.2.08

Where and how can I grab the latest?

NaomiN commented Sep 24, 2015

Thanks a lot, what about non-min version as well?

NaomiN commented Sep 24, 2015

Latest ui-router.js file didn't resolve the issue for me. My code is the following:

$state.go('category', { categoryId: $scope.searchParameters.categoryId, createDaily: createDaily },
{ reload: true, inherit: true, notify: true });

The Init of the corresponding controller is not firing and the server's method is not called.

NaomiN commented Sep 24, 2015

Looks like the issue I was having was actually related to a bug we had in our directive. Once we commented out 1 line of code (important, though), I didn't have the issue anymore

This thread is undead.

@mgamsjager thank you so much for your hint! After hours of debugging and searching for less-than-optimal alternatives, adding cache-view="false" tom my ionic view for reloading the same view worked!

@mgamsjager I owe you a beer!

edgahan commented Oct 26, 2015

Just quickly, in case it helps other: Adding cache: false to the state did not work for me, I had to add cache-view on the ion-view element like this: <ion-view title="my title" cache-view="false">

@hpawe01 thanks, work for me

i lost 4hours on this bug, gg

Why was this closed? I'm using v0.3.1 and this issue still is happening. I've even tried multiple of these solutions without any luck.

$state.transitionTo($state.current, angular.copy($stateParams), { reload: true, inherit: true, notify: true });

I'm still not seeing my controller constructor being hit.

Member

eddiemonge commented Oct 19, 2016

It was closed because it was fixed in 7344342

If you are still experiencing it, please open a new issue to track it.

hhsadiq commented Nov 28, 2016

I was having this issue, able to solve it using solution mentioned in ui-sref-active section of docs.

<a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment