Ionic Beta14: how to clean the Cache for a specific view?

Hi everybody. The new caching feature is great, but I’m facing an issue and can’t believe Ionic Team hadn’t thought about a solution for this, I’m quite sure I’m missing something. The problem is:

I have a view with a list of records.
Tapping on the record will bring me to a different page where the user can edit the record. Once finish editing, the user taps a button and comes back to the view with the list of records.

But the view with the list of records is cached! So in the records list the user still sees the record title before he edited it!

How can I tell Ionic something like: hey man, the user who is visiting events.list state is coming from the events.event.edit state --> clean the cache of the events.list!

Thanks

5 Likes

You can clear the cache for a specific view using cache-view="false

http://ionicframework.com/docs/api/directive/ionView/

6 Likes

Thanks mhartington. But - if I’ve well understood - this attribute should be set in app.js (in the routing policies) or as attribute of the view. But this way, the view is OR always cached OR always not cached. Intestead I want to be able to dynamically decide: bring me to the state xx.yy without using the cache, OR bring me to the state xx.yy using the cache (if available). Did I succeeded in explain? Thanks

4 Likes

IMHO, you can’t alternate dynamically.
But in my app, I have the exact same case and I make use of this strategy: using a $cacheFactory (from Angular) as intermediate between both views (list and detail).

=>
On the list controller I have a function call showItem(itemId).
What I do first is to add all the list data, (let’s say $scope.myList) to the cache.
On the show page, when I edit something, I retrieve the corresponding item from the cache with the specific itemId and mutate it.
Now, when going back to my list view, I strictly don’t want to make an ajax call to refresh data (it’s the goal of the pull-to-refresh IMO and moreover, I would lose the scroll position, bad !), so… I use the cache values ! Basically, a simple conditional is: “If there’re data in cache, display them. Otherwise, load from database”.

You would tell me: wow you keep all the data in memory, bad !
But the point is the cached view already caches the $scope values (in order to repopulate them), therefore, as being simple references, it’s not such a memory waste ! :wink:

What I do is that I manually remove all data in cache (to force a refresh) when I want according to the conditional.
I remove it when I click on any ion-tab, through the on-select attribute, or when I select some filters (buttons) near to my list to refresh the whole list.

Hope that helps :wink: => it’s just about a good algorithm :wink: in TDD :wink:

3 Likes

Thank Mik378, thanks for sharing your solution. It works and makes sense. I’ll use this strategy. Anyway I’m still quite “shoked” that the great Ionic Team had not thought to a function to call to release/delete the cached version of a view. Because without this (simple) function, their caching built-in feature can transform in a double-edged sword. What to say…I hope they will include it in the next beta!

3 Likes

Hi @Delfins,

I think ionic and angular already provide you with the tools required to achieve your goal. As mentioned by @Mik378 you can isolate your data in a cache factory or provider to manage the data sync between your views. I like this approach better than risking performance losses through destroying cached views (especially views that contain long lists). View caching was a massive leap forward for Ionic.

Hopefully this hasty codepen aids my explanation

See the Pen vEKmPz by Jeremy (@jeremyrussell) on CodePen.

“Anyway I’m still quite “shoked” that the great Ionic Team had not thought to a function to call to release/delete the cached version of a view”

You should see a cached view as itself a double-edged sword.
Indeed, a cached view can be updated thanks to those kind of great events: ion-view - Directive in module ionic - Ionic Framework (in the middle of the page).

Why I use a cache factory to achieve the classical list/detail view pattern, is for 2 reasons:

  1. Don’t want to trigger a new Ajax call in a $scope.$on(‘$ionicView.beforeEnter’) for performance reason.
  2. If I did the ajax call, I would lose the “previous” scroll position.

So to sum up, yes Ionic thinks about this case :wink: since you can update an EXISTING cached view through those events.
Better performance than “cleaning” them and recreate them.
I typically use this $scope.$on('$ionicView.beforeEnter') event to refresh my data through an Ajax call when I click on the tab directly (with no angular cache so), expecting a refresh.

Hope I’m clear :wink:

10 Likes

Looking at the source, it looks like you can pass cache: false as a state param, as in $state.go('otherState', {cache: false}) (?), but I haven’t figured out how to use it yet.

4 Likes

Thanks @colllin , this seems such a great discovery! Anywhay, I’ve tried but seems the cache is still there…maybe Ionic Team has expected to include this function, but today it is still not up and running…

See @Mik378’s answer, pretty great answer.

Also, we do have it document that you can pass cache:false in your states.

http://ionicframework.com/docs/api/directive/ionNavView/#Caching

1 Like

Oh bummer, so it’s still static. Equivalent to cache-view="false". Though it might be possible to dynamically update the state definition by calling $stateProvider.state(...) with cache: false immediately before navigating to that state, and then set it back to cache: true after the navigation.

3 Likes

Good idea! ButI’ve tried doing this in my controller:

$stateProvider.state('mainmenu.events.list', {
                cache: false,
                url: "/events/list/:year/:month/:day",
                views: {
                'details-tab' :{
                  templateUrl: 'templates/events/events-list.html',
                  controller: 'EventsListCtrl'
                }
                },
                data: {
                // This tells Auth0 that this state requires the user to be logged in.
                // If the user isn't logged in and he tries to access this state
                // he'll be redirected to the login page
                requiresLogin: true
                }
            });

But it tells me $stateProvider is not correct:

ERROR:Error: [$injector:unpr] Unknown provider: $stateProviderProvider ← $stateProvider ← AgendaAddCtrl

I’ve included it in parameters of the Controller with .controller(‘EventEditCtrl’, function($scope,$stateParams, $stateProvider, […]

How can I correctly update the state definition from the Controller?

Thanks

1 Like

@Mik378 I tried to implement your solution by using the $ionicView.beforeEnter event but it’s not working.

My state resolve:

dashboard.config(function ($stateProvider) {
	$stateProvider
		.state('dashboard', {
			url: "/dashboard",
			resolve: {
				'dashboard': ['Dashboards', 'Restangular', function (Dashboards, Restangular) {
					return Dashboards.post().then(function (result) {
						return Restangular.oneUrl('newDash', result.data).get();
					});
				}]
			},
			templateUrl: "./app/dashboard/dashboard.html",
			controller: 'DashboardCtrl'
		});

});

The controller:

dashboard.controller('DashboardCtrl', ['$scope', 'dashboard', function ($scope, dashboard) {

	// Old way
	//$scope.drafts = dashboard.data.drafts;

	// New way
	$scope.$on('$ionicView.beforeEnter', function() {
		console.log('beforeEnter');
		$scope.drafts = dashboard.data.drafts;
		$scope.pendings = dashboard.data.pendings;
	});

}]);

When the view is loaded for the first time, the resolve part is called as expected, and also the event callback. Then I navigate to a detail view, and go back to the master view. This time I can see the resolve part called, and also the event callback, but the view displays the old data. The $scope.drafts = dashboard.data.drafts; is not working whereas dashboard.data contains the updated data.

What if you use the enter event instead of beforeEnter.
Perhaps it’s a matter of order that causes your outcome.

The dashboard parameter of the controller is still the old one. The resolve is called, I see in the log the id of the new dashboard, and then the $ionicView event is triggered, and this time the dashboard id is not the same as the one from the resolve. It’s an old reference.

The documentation states:

Because scopes are not being destroyed and recreated, controllers are not loading again on a subsequent viewing.

Maybe this is the reason why the parameters passed by resolve are not refreshed.

I have been reading this post a couple of times because I am fighting with this as well. Isn’t the $ionicView.enter defeating the purpose?

Imagine a CRUD. I have a page with a list of items which I get from a $cacheFactory, that list contains X references to X items. I edit one of them on another page, I mutate the value of one of those items and when I go back, the list is updated. The issue comes when you add / delete items. Your list is not going to add or remove references to it (if using $cacheFactory) so you here seems to suggest this $ionicView.enter to grab the new list. The issue I see with that is that the list is going to be updated every time I go to that page. Isn’t that the same as cache: false? At the end of the day I am recreating the list every time.

I could set a flag when the list changes in size to refresh it, but I am not too fond of the idea.

1 Like

I’m having the same issue only when I add/delete items. I’ve tried a number of solutions but still no answer.

Does anybody know the best way to handle refreshing the list after adding another item to it in another controller?

1 Like

I ended adding a flag into my service. Then I put a $ionicView.enter event on the controller which will always request new data. On the factory, when the data is requested I check the flag, if it is true, I return a promise with the data, if it is false, I return an empty promise. Then back on the controller, if the promise returns data, I replace my old list with the new one and if it is empty, I do nothing.

3 Likes

I’ve been following this thread as the caching feature has caused us some pain although we really want to use it. The issue I have is regarding multiple users. What is the proper way to clear the entire cache for someone that has logged out so a new user doesn’t see anything from the previous user?

2 Likes

@henry74 not sure if still relevant:

$ionicHistory.clearCache();