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

feat: Add a method to empty/flush Cached Views #2939

Closed
gio82 opened this issue Jan 14, 2015 · 57 comments
Closed

feat: Add a method to empty/flush Cached Views #2939

gio82 opened this issue Jan 14, 2015 · 57 comments
Assignees
Milestone

Comments

@gio82
Copy link

gio82 commented Jan 14, 2015

Type: feat

Platform: all

I have an app that needs a login to see personal informations.

Since ionic beta 14 and the introduction of Cached Views I have big trouble when a user logoff and login with a different user.

The new user after the login still see the cached views of the previous user.
At the moment it seems that the only solution to avoid this is to disable everywhere the cached views ( $ionicConfigProvider.views.maxCache(0); ).

It would be very useful to have a ionic.flushCachedViews() method to clear all the cached views.
I would call this when a user logoff.

@gio82
Copy link
Author

gio82 commented Jan 14, 2015

Ok, sorry I just realised $ionicHistory.clearCache();.
But I'm not able to work with it.
When I try to use it strange things happen to my app.

@gio82
Copy link
Author

gio82 commented Jan 14, 2015

I'm still playing with this.
Very often when I try to use:

  • $ionicConfigProvider.views.maxCache(0);
  • $ionicHistory.clearCache();
  • cache: false, (inside tab abstract state)

I have the following error:

0     874666   error    Error: Attempted to assign to readonly property.
ChildScope@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:21459:42
$new@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:21467:40
compositeLinkFn@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:14866:38
compositeLinkFn@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:14890:24
nodeLinkFn@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:15526:35
compositeLinkFn@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:14887:23
publicLinkFn@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:14766:45
appendViewElement@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:47324:11
render@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:45864:58
init@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:45784:26
render@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:47225:18
register@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:47181:16
updateView@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:50834:31
http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:50811:21
$broadcast@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:22496:33
http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:39883:32
processQueue@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:20962:29
http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:20978:39
$eval@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:22178:28
$digest@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:21994:36
$apply@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:22282:31
done@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:17439:53
completeRequest@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:17629:15
requestLoaded@http://192.168.1.100:8100/lib/ionic/js/ionic.bundle.js:17570:24

@acveer
Copy link

acveer commented Jan 16, 2015

@gio82 I encountered the same issue, but was able to disable cache with one of below 2 ways instead of entire app from $ionicConfigProvider. Thanks to @Sreekanth on the ionic forum. http://forum.ionicframework.com/t/issues-w-routing-state-go/9418/15?u=acveer

Disable cache within state provider:

$stateProvider.state('myState', {
cache: false,
url : '/myUrl',
templateUrl : 'my-template.html'
})

Disable cache with an attribute:
ion-view cache-view="false" view-title="Home">Home </ion-view

note: purposefully omitted '<' & '>' in the above HTML as the comment section is trying to render it.

@gio82
Copy link
Author

gio82 commented Jan 16, 2015

Yeah, I ended up with the same solution but I consider this a turnaround.
All my views are now not cached. :(

I hope and guess driftyco will work to fix these bugs.

Thanks @acveer for your help.

@felquis
Copy link

felquis commented Jan 19, 2015

I really need something like this.

$ionicHistory.clearCache() should remove all cached views, this method doesn't touch in the previous view, this is unexpected in my opinion. I need a method to remove all the cached view's content programatically, would be very useful.

@pauljandrew
Copy link

+1: Cached views are awesome, just need a way to clear them all on logout.

@JerryBels
Copy link

+1

clearCache should empty all the cached views, no matter where they stand or what is the parent state.

I will add some of my observations.

  • Views with stateParams are cached without taking it into account ! That means a user page (that use the user ID as a parameter) would be cached, and displayed when trying to look at another user ! That's a big issue IMHO. Should I create a specific post for it ?
  • Clearing one specific view should be possible using the view "name" attribute, if it exists.
  • Controllers remains active in cached views. This should be wanted or not, so it should be a parameter to set, whether to pause them when cached or not.

@adamdbradley
Copy link
Contributor

Would someone be able to reproduce this error using the nightly build? Thanks

@adamdbradley adamdbradley self-assigned this Feb 12, 2015
@henry74
Copy link

henry74 commented Feb 13, 2015

+1

@osahner
Copy link

osahner commented Feb 14, 2015

Looks good to me. For me, the error no longer occurs.

@JerryBels
Copy link

@adamdbradley okay, I spent the day at reducing my project to get a mcve that could help you guys. I'm not sure I really succeeded in this, but I did reduced it enough to demonstrate some of the issues clearly. I modified the names and all this, but it's close to the actual structure of my real project. I think it's a common pattern - there is a list of events, in each event there is a list of users, and each user has its own page.

Codepen - http://codepen.io/JerryBels/pen/ogEdaK

Now, you can easily see some bugs here, if I'm not mistaken. First, when selecting a user, and then coming back and selecting another, it does display the first user's page. That shouldn't be the case since it uses stateParams. Note that the bug must be somewhat linked to the multiple nested states, since I failed to reproduce it on a simple states architecture (but I'm still very young with Angular so I will let you guys figure it out).

Second, when displaying the menu and switching event (clearing the cache happens there), the first time you do that it's the previous event that displays again (you can see its name in the menu). The next tries are good.

I think that's not everything but it's all I could get with this simplified example. I really hope it will help you guys.

Good luck ! :-)

@dd36
Copy link

dd36 commented Feb 20, 2015

+1

@andycaramba
Copy link

+100
$ionicHistory.clearCache() does not work

@FdezRomero
Copy link
Contributor

Forget my last comment, $ionicHistory.clearCache() does work in the beta 14, nightly 995

@JerryBels
Copy link

I don't think so. The bugs demonstrated in my codepen above still occurs. Lets say it does work sometimes.

@3h3c
Copy link

3h3c commented Mar 8, 2015

+100
still present. tested with v1.0.0-rc.0-nightly-1122.

is a workaround available?

@3h3c
Copy link

3h3c commented Mar 9, 2015

angular/angular.js#9128

looks like the same bug

@adamdbradley
Copy link
Contributor

Sorry everyone, but I'm not being provided with an example of it not working. I just reviewed the codepen and clear cache is working when fired from $ionicView.enter event. I'll need a detailed codepen, and detailed description showing exactly how it's not working, and a full description of what elements should be removed.

@JerryBels
Copy link

@adamdbradley - in the codepen I provided ( http://codepen.io/JerryBels/pen/ogEdaK ) the first "switch event" doesn't work, the cache is not cleared, the same event shows up. I added a title for it to be more visible. This is a clearcache bug.

Besides, even if it's not a clearcache bug, it's a huge cache bug that when you get to a user page it doesn't take its id (which is a state parameter) into account, showing the page of the user who was first opened because that page is cached ! Should I create another thread for this issue to be taken into account ?

@adamdbradley
Copy link
Contributor

  1. App loads at /#/app/guests
  2. Click side menu toggle
  3. Click switch event button
  4. Clear clearCache should be called because welcomeCtrl entered
  5. Inspect the DOM, and .....

Details like this help me to debug. With you're app, please describe in detail how to see what you're seeing, and what I'm looking for.

Note: You're not using lifecycle events, so controller logic is only going to fire once, which is what you're seeing in your profileCtrl. But I think the biggest issue is that the app.profile state is set as an abstract state, which confuses the app and routing and a lot of its logic is skipped over.

@JerryBels
Copy link

Okay @adamdbradley, sorry :)

So, steps 1 to 4 are good...

  1. App loads at /#/app/guests on a given event (default 1)
  2. Click side menu toggle
  3. Click switch event button
  4. ClearCache should be called because welcomeCtrl entered
  5. Choose a different event (for example, 2)
  6. The first event will still be loaded, cache have not been cleared.
  7. Do again steps 2 to 5
  8. Everything works fine now.

To be completely honest, I have much more problems with cache on my real app but have a hard time minimizing it to a mcve while keeping the bugs, so I stopped when I observed this bug. Maybe solving it will solve the rest.

As of the abstract state, I thought I was forced to use it, since the doc ( https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#abstract-states ) says it's usefull to fulfill my use case ( "insert a template with its own ui-view(s) that its child states will populate", $scope and resolved dependencies inheritance...) but it looks like the same state without being stated as abstract does exactly the same thing... And then the cache does work well. Did I misunderstood what abstract is good for ? Also, when disabling the cache completely, it works even when stated as abstract without any issue.

@JerryBels
Copy link

@adamdbradley following your message about abstract not being usefull, I just took every abstract state off, as well as users concept. Here is the minimized codepen : http://codepen.io/anon/pen/Joxdeb

Now the clear cache fails all the time, which demonstrate much better the issue (I still feel it's linked to nested states). To reproduce simply :

  1. App loads at /#/app/guests on a given event (default 1)
  2. Click side menu toggle
  3. Click switch event button
  4. ClearCache should be called because welcomeCtrl entered
  5. Choose a different event (for example, 2)
  6. With Chrome debug tools, you can see that the local storage "event" value changed.
  7. The first event will still be loaded, cache have not been cleared.
  8. Do again steps 2 to 6 to see it fail again and again.

I hope that helps to resolve the issue !

@buunguyen
Copy link

+1. $ionicHistory.clearCache() doesn't work for me. Situation:

  1. Login as user 1
  2. Go to profile page, use state resolve to get user info and display
  3. Logout, clear history, then login as user 2
  4. Go to profile page, state resolve is invoked and returns user 2 info correctly, but user 1 is still displayed (i.e. view and controller are still cached)

I have to set cache: false in the profile page for it to work, which isn't ideal because I still want the cache to work until user logs out.

Would be great if $ionicHistory.clearCache() just clears everything. Will be a useful action when logging out and logging in as a different user because data of most pages will change.

Version: Ionic 1.0 RC1

@felquis
Copy link

felquis commented Apr 6, 2015

@buunguyen I fixed it by creating a state that only check if the user is logged in or logged out, just like this:

  1. User go to profile state
  2. User logout from profile state
  3. Logout empty all the data in services
  4. Logout redirect user to checklogin
  5. Checklogin will ensure the user is logged out with the server side
  6. Checklogin redirect the user to login state
  7. Login state call $ionicHistory.clearCache() and $ionicHistory.clearHistory() inside $ionicView.enter
  8. Now, the only views in the DOM is, the checklogin state and login state.

The main problem with $ionicHistory.clearCache() is that this method doesn't remove the previous view. So, if the previous view is the checklogin view, the profile view is correctly removed from the DOM.

History stack is like a array ['view 0', 'view 1', 'view 2'], in this case, it's ['login', 'checklogin', 'profile'], clearCache will keep the indices 0 and 1 (1 is the back view) and remove indices 2+

But there's differences by using clearCache when $ionicView.enter, $ionicView.afterLeave, for example, when I log out a user, if I run clearCache() inside $ionicView.afterLeave it seems to correctly remove the back view from the DOM.

This is related to http://forum.ionicframework.com/t/clearcache-possible-bug/16532

@carlosfilho88
Copy link

@felquis can you post a Codepen example, please?

@buunguyen
Copy link

@felquis thank you for the tips. What I actually did was moving the clearCache() call from post-logout to post-login and it appears to work, probably because my login view is before all others in the stack.

@mhartington mhartington added this to the 1.0.0-rc3 milestone Apr 13, 2015
@JerryBels
Copy link

Thanks for the commit guys, I will test it and feedback whenever it's included into ionic.bundle.js.

@barocsi
Copy link

barocsi commented Oct 28, 2015

+1 here does not work
$ionicHistory.clearCache();
$ionicHistory.clearHistory();

@mousenine
Copy link

$ionicHistory.clearCache() did not work for me either. Timeouting a call to $ionicHistory.clearCache() resolved the problem:

$timeout(function(){

    $ionicHistory.clearCache();

}, 300);

@barocsi
Copy link

barocsi commented Oct 29, 2015

Tested, still get cached views.

@darshanrampatel
Copy link

Yep, I'm also seeing this on v1.1.0.

Wrapping it in a $timeout doesn't work either, nor does using the promise version.

@jordidiaz, how are you clearing this for each view? The docs don't mention that you can pass in a state?

@jordidiaz
Copy link

Hi @darshanrampatel

To clear view data (for example, has mentioned by @eroh92) I listen to a 'logout' event and clear the data in the event callback function. It's a manual work but if I don't do that the previous user's data is shown to the just logged user.

If someone has a better method, I'll be very thankful.

@FWiner
Copy link

FWiner commented Nov 2, 2015

i also have this issue

in my signInCtrl:

 $scope.$on('$ionicView.beforeEnter', function (e) {
            $scope.hideBottom.hide = true;
            console.log($ionicHistory.currentStateName());
            console.log($ionicHistory.currentView());
            $ionicHistory.clearCache();
        });
not working

 function dosignin(item){
            $ionicHistory.clearCache().then(function(){
             authService.doSignin(vm.userInfo).then(function(data){
                    console.log('controller then ---------------------');
                    console.log(data);
                    if(data.code == 'ACK'){
                        $state.go('main.expenses');
                    };
                });

})
     } 

its working for me when i add the function in the doSignin FUNC
but not perfect
cacheView also appear in shortTime when i forward to state('main.expenses')

@FWiner
Copy link

FWiner commented Nov 2, 2015

and this also help me in my signoutCtrl

authService.doSignout().then(function(result){
if(result.code == 'ACK'){
$timeout(function () {
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
console.log('clearing cache');
},300)
hideSheet();
$state.go('app.signin');
}
})
also not perfect for me
and how to clear the factory data when i logout

@ZenSide
Copy link

ZenSide commented Nov 9, 2015

Thanks to @mousenine , wrapping with a timeout works for me too (seems it just need to be on the same digest, so no need to set a number of ms).

$timeout(function() {
    $ionicHistory.clearCache();
    $ionicHistory.clearHistory();
});

@sargismarkosyan
Copy link

This one works for me

$ionicHistory.clearCache().then(function() {
    $state.go('...');
});

@gauravarora
Copy link

None of the above solutions worked for me and I tried all of them over a span of a few hours. :(

@JerryBels
Copy link

@sargismarkosyan gave the solution indeed, I found out the same. Waiting for the promise to resolve before navigating to the next state works perfectly.

@bensinclair
Copy link

I apologise for jumping in on a closed topic but here's something for those who this is not working for.

Have you considered that the issue might be that you are storing certain data in a global variable or within a service/factory rather than the issue being that Ionic is not clearing the cache?

This happened to me. Like everyone else, I was trying to blame it on Ionic and the clearing of cached views not working but the issue was because I wasn't clearing a global variable that was storing my data.

That, said, to ensure the clearing of cache works in Ionic, from my experience like others above, putting the clear cache function in a $timeout is the only way I was able to get it to work:

$timeout(function() {
    $ionicHistory.clearCache();
    $ionicHistory.clearHistory();
}, 100);

@ZenSide
Copy link

ZenSide commented Dec 3, 2015

Something to notice is that since 1.1.0 release, clearCache() returns a promise called when cache is flushed. Didn't test it myself, but it seems to be the clean way to do it.

@sergeykuzmich
Copy link

By docs it must return promise, but it doesn't.
Cannot read property 'then' of undefined

So, almost year is gone and there is no answer to question "How to clear cache".

@mlynch
Copy link
Contributor

mlynch commented Dec 5, 2015

@sergeykuzmich there have been a number of answers to the problem, and yes, the function does return a promise:

screenshot 2015-12-05 10 16 41

There's a high chance this service is being used incorrectly, or the issue is coming from somewhere else (including user code). However, since this comment has gotten a lot of questions over the last year, it's clear this function is causing some confusion and/or is buggy.

To help us fix this, can anyone confirm this is still happening in a recent version of Ionic? I'm testing some of the code pens and not really seeing any issues with nightly/1.1.1.

Any other recent test cases will help us figure out what's going on.

@mlynch
Copy link
Contributor

mlynch commented Dec 5, 2015

Okay, noticing a few things here. First, you need to call clearCache after the $ionicView.enter lifecycle. However, it also needs to wait one digest step after, since we won't know the old view is not the active view until after. In the short term, use this code:

$scope.$on('$ionicView.enter', function() {
  $timeout(function() {
    $ionicHistory.clearCache();
  });
});

We will look to a better solution. Some WIP: https://github.com/driftyco/ionic/tree/2939-view-events

@mlynch
Copy link
Contributor

mlynch commented Dec 5, 2015

Just landed in master: 06ef682

With this fix, this code will work to clear any cached views behind the view that just entered:

$scope.$on('$ionicView.enter', function() {
  $ionicHistory.clearCache()
});

Will work. Mind giving master a try and letting me know if it resolves your issues?

@sergeykuzmich
Copy link

@mlynch thanks for your response

I've got a little different use case of clear cache. I've got feed of some data, by clicking to each item of data you see description of item and there is 'delete item' button. After pressing it item must be removed and user goes to feed screen and I need to refresh feed screen (reset cached view) and completely reload feed, because deleting one item can delete others connected items. So I need to clear cache after some action.

I've tried to use $ionicView.afterLeave event but nothing is changed, also I tried to use $timeout function - it is better but it did not clear cache for view I go and clear cache for others.

So,

$scope.$on('$ionicView.afterLeave', function() {
  $ionicHistory.clearCache()
});
$state.go('feed');

doesn't work, and

$timeout(function() {
  $ionicHistory.clearCache()
}, 100);
$state.go('feed');

works only if I have middle step such as

$timeout(function() {
  $ionicHistory.clearCache()
}, 100);
$state.go('middle');

and in the 'middle' call $state.go('feed')

I'm working with private business app and not sure can I show it in CodePen or not. I've tried to repeat behavior in CodePen to show what I want to get.

@git1120
Copy link

git1120 commented Dec 6, 2015

could u please provide codepen example without using factory,
just using controller.

Thanks

@gouroujo
Copy link

The code provided by @mlynch is working for me:

$scope.$on('$ionicView.enter', function() {
  $ionicHistory.clearCache()
});

it must be placed after the logout, in my case in the welcome controller

@protonmesh
Copy link

This is what I use during logout

 // After logging out, ensure hitting back button from login screen doesn't return to the account settings page
      $ionicHistory.nextViewOptions({
          historyRoot: true,
          disableBack: true,
      });

      $ionicHistory.clearCache().then(function () {
          $ionicHistory.clearHistory();
      });

Works for me

@Manish905
Copy link

i am using bellow code but not entering in block to show alert.
$ionicHistory.clearCache().then(function () {
alert();
$ionicHistory.clearHistory();
});

@rig1
Copy link

rig1 commented Jan 22, 2016

This woked for me

$timeout(function(){
$ionicHistory.clearCache();
}, 500);

$state.go('app.login');

@Manish905
Copy link

can any body solve my issue ?
my issue are that , i am installing another apk in my android phone but before of this an app installed (Build in ionic using angular with vs2015) by me, then i am try to install another one but its
unable to install.

@glaucomorais
Copy link

This worked for me.
ionic --version says 1.7.5

$ionicHistory.clearCache([$state.current.name]).then(function() {
  $state.reload();
});

@SilvaCoder
Copy link

SilvaCoder commented May 17, 2017

Well this is an old issue, but for anyone that's coming 2017 or later I will explain what really happens and how to solve it:

The code of $ionicHistory.clearCache():
clearCache: function(stateIds) { return $timeout(function() { $ionicNavViewDelegate._instances.forEach(function(instance) { instance.clearCache(stateIds); }); }); },
So, as you can see, it takes 1 parameter cllaed stateIds which is an array of stateId. Indeed i struggled to find out that stateId is nothing more than stateName.

So, let's go deeper. The code of $ionicNavView.clearCache which is used in the line above "instance.clearCache(stateIds)" is:

`
self.clearCache = function(stateIds) {
var viewElements = $element.children();
var viewElement, viewScope, x, l, y, eleIdentifier;

for (x = 0, l = viewElements.length; x < l; x++) {
  viewElement = viewElements.eq(x);

  if (stateIds) {
    eleIdentifier = viewElement.data(DATA_ELE_IDENTIFIER);

    for (y = 0; y < stateIds.length; y++) {
      if (eleIdentifier === stateIds[y]) {
        $ionicViewSwitcher.destroyViewEle(viewElement);
      }
    }
    continue;
  }

  if (navViewAttr(viewElement) == VIEW_STATUS_CACHED) {
    $ionicViewSwitcher.destroyViewEle(viewElement);

  } else if (navViewAttr(viewElement) == VIEW_STATUS_ACTIVE) {
    viewScope = viewElement.scope();
    viewScope && viewScope.$broadcast('$ionicView.clearCache');
  }

}

};
`

And as you can see in the code, this clearCache DOES NOT CLEAR ALL CACHES, instead, it destroy all cached views that matches a value in the stateIds array. If there's no parameter IT JUST DESTROY THE ACTUAL VIEW.

So the solution for this, using just the Ionic way is to call $ionicHistory.clearCache() with all your state names in an array as parameter.

E.g:
$ionicHistory.clearCache(['login', 'map', 'home']);
I cannot belive any Ionic developer didnt dug into the code before, or missed this simple datail.
I Hope someone takes advantage of this, even being so late.

UPDATE: Just to make it crystal clear, i want to point out where the bug itself is (if we can call it bug), maybe can be handy for devs:

self.clearCache = function(stateIds){

[...]

     var viewElements = $element.children();

}

What the whole function does is basically:

  • Get all elements using JQLite
  • Loop the elements
  • Check if an element equals one in the StateIds array and destroy it; go to next element.
  • Check if element in the loop is cached or active, and in both true cases destroy it

I wont dig deeper into this but debugging it i could see that the elements gotten from var viewElements = $element.children(); is not an array of all your views content, not even the cached ones, intentionally or not it does not loop through out all your states to clear all those that matches 'ACTIVE' or 'CACHED'. If you want it to loop through ALL your states and destroy all cached views and data you need to explicity pass the stateIds array parameter.

Besides there's another strange behavior, because when i was debugging it i saw when the var viewElements array was filled up with 2 elements, and these 2 elements were from the same state, one resolved to 'CACHED' another resolver to 'ACTIVE', even resolving to the 2 types used in the if conditions the cache was not cleared at all.

I personally think that this is somekind wrong implemented or is wide used wrongly. The fact is that there's a lot of people cracking their heads on this and devs don't even give this simple explanation.

@ionitron-bot
Copy link

ionitron-bot bot commented Sep 2, 2018

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.