4

I am using ui-router with Material Design's tabs in order to load tab content dynamically in an ngGrid.

Every view has its separate controller with a service which requests the data. Any ideas on how I can configure ui-router to initialize the data only once for each tab?

Currently, every time I click on a tab a new request is being fired and ngGrid is reinitialized.

ng-router config file, just in case:

    $stateProvider
        .state('tab1', {
            url: '/tab1',
            views: { 
                'tab1': {
                    templateUrl: 'tab1.html',
                    controller: 'tab1Controller'
                }
            }
        })
        .state('tab2', {
            url: '/tab2',
            views: { 
                'tab2': {
                    templateUrl: 'tab2.html',
                    controller: 'tab2Controller'
                }
            }
        })
        .state('tab3', {
            url: '/tab3',
            views: { 
                'tab3': {
                    templateUrl: 'tab3.html',
                    controller: 'tab3Controller'
                }
            }
        });
Loukas Avramidis
  • 519
  • 3
  • 10
  • 24

1 Answers1

2

UPDATED

In case, that data are different for each tab, we have to options.

  • use inheritance (view inheritance),
  • use Services

The first case will mean, that all states do have same parent. This parent declares Model = {}. Every sub-state can later access this Model and add or use the data

var data = Model.DataForTab1;
if(!data){
  data = loadData();
  Model.DataForTab1 = data;
}

next time, we come to this tab, we can reuse existing, in parent $scope referenced data Model

The second approach is to use caching inside of a special services for each data load. Such service would have almost the same logic (return loaded cached data or load them)

Difference? Services will have longer life time (through whole application). The parent of tabs will keep the data JUST until we go to another parent state.

ORIGINAL part

If data are the same across all the states, the most suitable way (I'd say) with UI-Router, is to

  • introduce one common parent state,
  • use resolve in that parent (will be executed just once)
  • inherit from it, all children can get such data:

Check this Q & A

// virtual parent 'root'
$stateProvider
  .state('root', {
    abstract: true,
    template: '<div ui-view></div>',
    resolve: {objectX : function() { return {x : 'x', y : 'y'};}},
    controller: 'rootController',
  })

  // each state will declare parent state
  // but its name and url is not effected
  .state('tab1', {
    parent: "root",
    url: '/tab1',

Check more here and the working plunker

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Nope, the data in each state is different as are the controller. – Loukas Avramidis Mar 26 '15 at 15:38
  • How can they be loaded only once? if they are different? you mean when switching among the tabs? – Radim Köhler Mar 26 '15 at 15:38
  • Yes, sorry if I wasn't that clear. So for example, if I click on tab1, the data from tab1 is loaded. Then if i reclick it, it won't be loaded again. Thanks for your answer by the way. – Loukas Avramidis Mar 26 '15 at 15:43
  • I tried to show you the way in updated answer. My preferred way is the parent... and a `Model`. In fact the solution is still very similar. We should introduce parent state and use inheritance. Other way is standard service ... which is singleton and can keep the data for ever... – Radim Köhler Mar 26 '15 at 15:46
  • I will try your solution out, and be back at you. Thanks! – Loukas Avramidis Mar 26 '15 at 15:51
  • I did some tinkering, and I am currently working with 'resolve'. Still looking for a solution thought. As far as I know, I can only use $stateParams in resolve, which makes things a little more complicated. However, I am a little bit frustrated concerning 'reload'. Shouldn't the default value of 'reload: false' have solved my problem in the first hand? – Loukas Avramidis Mar 30 '15 at 15:39
  • No. Resolve is luckily called any time we reach state. It is not cached. Just evaluated before state transitioning. So, as I showed you, we have to do more. My answer is THE answer. – Radim Köhler Mar 30 '15 at 16:01
  • Just figured it out, used $cacheFactory and it works. Thanks a lot! – Loukas Avramidis Mar 31 '15 at 08:03
  • Great job sir. Enjoy might UI-Router ;) – Radim Köhler Mar 31 '15 at 08:03