45

I'm currently working on a Angular/Ionic/Cordova project and we've recently upgraded to the latest Ionic beta. From the version the project was using before, this introduced the view cache. It has also however introduced an issue in doing so.

The application is customer-facing and is very data-centric. A user must authenticate to view data associated with their account, currently however; when a user logs out, and logs into another account, because the view(s) are still cached they are presented with the views of the last account.

The app should still cache the views when the user is logged in, as it helps make the app feel much quicker, but the cache should be purged when a user logs out.

Setting cache-view="false" is not an option, as it would completely disable the cache.

I've also tried setting $ionicConfig.views.maxCache(0); and then back to the default of 10 in the hopes that it would purge the cache in doing so, but it had no effect.

The last thing I can think of to do is fire an event when a user logs in that refreshes all data that's currently loaded into the views - however, this would take a bit more effort than I feel it should.

Is there a way to simply clear the view cache?

Seer
  • 5,226
  • 5
  • 33
  • 55
  • 1
    I would also like to see an answer to the question as this change has disturbed my workflow. I find that the maxCache(0); method just disables caching of the controllers (so they are reinstantiated whenever they are used). On Mac OSX, my solution to this problem so far on Chrome is to right click on the refresh button and select 'Emtpy Cache and Hard Reload'. – jbeck Feb 23 '15 at 15:42

5 Answers5

67

In the state definition in app.js you can add cache:false to disable caching (See Disable cache within state provider in the Ionic docs. Or, you can keep caching except when you know data has changed.

  • If you're already on the page, you can do, $state.go($state.currentState, {}, {reload:true})
  • If you're on another state and want to go back to the state that is normally cached but you want it to be refreshed, you can do, $ionicHistory.clearCache().then(function(){ $state.go('app.fooState') })

Note, the latter requires clearCache to return a promise. See the changes I made in this pull request and compare the implementation of clearCache that you have now with mine: https://github.com/driftyco/ionic/pull/3724

ABCD.ca
  • 2,365
  • 3
  • 32
  • 24
  • BRILLIANT. The "latter" point makes our use case of "switching accounts" braindead simple. One line of code. Thank you so much! – rinogo Nov 15 '16 at 00:17
  • 1
    Note: The "latter" solution here clears all views *except for the one that is currently active*. If you want to clear the active view as well, one solution is to 1. clear the cache, 2. navigate to the page to be refreshed, and 3. clear the cache again. E.g. `$ionicHistory.clearCache().then(function() { $state.go('app.fooState').then(function() { $ionicHistory.clearCache() } })` – rinogo Nov 15 '16 at 22:47
  • And just in case your ionic clearCache function doesn't return a promise, you can always wrap it like this: `$q.when($ionicHistory.clearCache()).then(function(){ $state.go('app.fooState') })` – Rabbi Shuki Gur Nov 05 '17 at 02:09
22

I stumbled across a similar scenario where logging in with another user was showing me stale/cached view. You can do cache: false at the state definition level but that entirely disables cache for that state in your app.

What you can rather do is clear all the cached view and history when user enters the signin/login state of your application (as you said). Seems ideal.

// code inside your signin controller

$scope.$on("$ionicView.enter", function () {
   $ionicHistory.clearCache();
   $ionicHistory.clearHistory();
});
Nirav Gandhi
  • 1,945
  • 1
  • 23
  • 32
  • I stumbled across a scenario that would always present a white page when logging in after logging out. Your solution easily fixed this completely functional and interactive white screen. – im3r3k Nov 23 '15 at 16:57
8

You can also do it by setting cache:false in your $stateProvider:

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

Are you searching for something like this?:

$ionicHistory.clearCache();

EDIT:

There is an issue in Ionic's github: Issue

Andoni Martín
  • 253
  • 1
  • 3
  • 10
0

Well this is an old issue, I will explain what really happens and how to solve it:

P.S: If you want to go straight to SOLUTION just scroll down right away.

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: SOLUTION $ionicHistory.clearCache(['login', 'map', 'home']); I cannot belive any Ionic developer didnt dug into the code before, or missed this simple datail. There's a lot of people who's aching for this.

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 that 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.

Marco Silva
  • 564
  • 5
  • 15