Keep UI state when view changes

I’ve been using Ionic/AngularJS in several projects and I’m always struggling on the same issue.

I process some data with several kinds of displays (list, map) and when the user clicks on an element, it redirects him to a details page.

It should be good if the framework allows us to keep the UI state of the previous view, so when the user clicks on the back button on the details page, the previous page holds infinite-scrolling position or google map state.

As a workaround, my details page are always modals so when the user wants to go back, the modal closes and the background content state is kept. Nevertheless, this is not an ideal way of coding because the code is way harder to understand, and some problems happens concerning memory (imagine that the details page is linked to another details page, so you have modals opening infinitely…)

Is there a way to keep UI state of a page?

Just to clarify, I’m not talking about variables state (easy to store: $rootScope, localStorage, POST variables, cookies…).

TL;DR: I have a google map, when I click on a marker, it’s redirecting me on a details page, when I go back, I want to get the google map state back, how can I do it?

There’s no way with ui-router. You can however do this the old way and create your own simple solution as I show below. Sorry for any mistakes, I’m writting this from the top of my head :smile:

Main container for example for the side menu or tabbed interface can be:

<div ui-view></div>

Then above put several nested views. If you have three tabs or three main pages, then add three nested views, for example:

<div ng-include="'about.html'" ng-show="isAboutShown"></div>
<div ng-include="'indexinfo.html'" ng-show="isIndexShown"></div>
<div ng-include="'exitadpage.html'" ng-show="isExitPageShown"></div>

The ng-include directive refers to templates, so nothing new. The ng-show however controls the visibility. Assume that the indexinfo.html is the initial start page. So you must define the $scope.isIndexShown = true and the rest of the variables false. You can do this in your controller just like this:

$scope.isAboutShown = false;
$scope.isIndexShown= true;
$scope.isExitPageShown = false;

Then in your side menu or on tabs don’t use hrefs as defined for ui-router, but just call a function that will change the visibility of the nested views by changing the scope variables. Below are example items from a side menu:

<ion-item nav-clear menu-close ng-click="showaPage('about');" >
<span translate>ID_ABOUT</span>
</ion-item>

<ion-item nav-clear menu-close ng-click="showaPage('index');" >
<span translate>ID_INDEX</span>
</ion-item>

<ion-item nav-clear menu-close ng-click="showaPage('exit');" >
<span translate>ID_EXIT</span>
</ion-item>

You can use the same for tabs or anything else. The key is to call the showaPage() function which will change the visibilty of selected views. It may look like this:

    $scope.showaPage = function(apage) {
        if (apage == 'index') {
            $scope.isIndexShown = true;
            $scope.isAboutShown = false;
            $scope.isExitPageShown = false;
        } else
        if (apage == 'about') {
            $scope.isIndexShown = false;
            $scope.isAboutShown = true;
            $scope.isExitPageShown = false;
        } else
        if (apage == 'exit') {
            $scope.isIndexShown = false;
            $scope.isAboutShown = false;
            $scope.isExitPageShown = true;
        }

        $rootScope.viewHistory.push(apage);
    }

And that’s all. You have persisten views that are not recreated each time you switch the view. The state is kept. You can even do a simple routing if you remember the history of pages in an array and then use the history for the back button navigation.

The disadvantage is that transitions between pages is lost, but you can easily add your own using the CSS and Angular animate features. This is however your homework :slight_smile: A big advantage of this solution is keeping the state and not recreating DOM each time and over again which means speeding up. It’s a perfect solution for simple apps which mobile apps are mostly. For a web app ui-router should be a better solution.

Let me know if this helped somehow :slight_smile:

Thanks for the time spent responding to my question. The solution you provided clearly works but is also clearly ugly :smile:

Have you tried ionic’s ionNavview. It fulfills the desired purpose. It maintains stack for recording view history as user traverse through app. On android devices it also works with hardware back button.

Not so beautiful, true, but works :slight_smile: If you need to keep the state I think you should save it and recreate on router state changes. You can use the events provided by the router.

2 Likes

But it can’t keep the previous state. Every time we go back, it reloads all.

I have the same problem with you. In my app, I have a google map, but every time I go back to map, it can’t save the previous map and it reloads all. I use the view navigation to change state but I don’t know how to keep the map when I change state.
Have you solved this problem? I’m really troubled.

The solution I found is to display the details page as a modal. So it’s keeping the Google maps state, and my list scroll position in background. And even if it was initially designed as a temp fix, it works fine!