1

https://plnkr.co/edit/bOZW1a9u62W1QA6cYjYj?p=preview

Expected

After Login all $states initialize, then after clicking a Ticker button, the only $states that should re-init are ticker, tags and social, but not feed.

Results

After Login all $states initialize, then after clicking a Ticker button all $states re-initialized. The feed should not.

enter image description here

How should the dashboard and feed module be architected to prevent this? At the moment I have the <feed-module></feed-module> inside the dashboard.html. Should it and the dashboard be further separated out in another in-between state/component? A container.component perhaps?

Full code

// Feed module
////////////////////////////////////////////////////////////////////////////////
var feed = angular.module('feed', ['ui.router'])

feed.config(function($stateProvider) {
  
  const feed = {
    name: 'feed',
    url: '/feed',
    templateUrl: '<em>Feed items go here.</em>'
  }
  
  $stateProvider.state(feed);
  
})

feed.component('feedModule', {
  templateUrl: 'feed-module-template.html',
  controller: function($scope, $state) {
    console.log('Feed init (only once)', $state.params);
  }
})

// RouterApp module
////////////////////////////////////////////////////////////////////////////////
var routerApp = angular.module('routerApp', ['ui.router', 'feed']);

routerApp.config(function($stateProvider, $urlRouterProvider) {
    
    $urlRouterProvider.otherwise('/login');

    const login = {
      name: 'login',
      url: '/login',
      templateUrl: 'login.html',
      bindToController: true,
      controllerAs: 'l',
      controller: function($state) {
        this.login = function() {
          $state.go('dashboard', {});
        }
      }
    }

    const dashboard = {
      name: 'dashboard',
      url: '/dashboard',
      params: {
        ticker: {},
        tags: {}
      },
      views: {
        '' : {
          templateUrl: 'dashboard.html',
        },
        'tickers@dashboard': {
          templateUrl: 'tickers-module-template.html',
          controller: function($scope, $state) {
            console.log('Tickers init', $state.params);
        
            $scope.tickers = [
              { id: 1, ticker: 'AAPL' },
              { id: 2, ticker: 'GOOG' },
              { id: 3, ticker: 'TWTR' }
            ];
            
            $scope.clickTicker = function(ticker) {
              console.log(' ')
              console.log('Ticker clicked!')
              $state.go('dashboard', { ticker: ticker });
            }
          }
        },
        'tags@dashboard' : {
          templateUrl: 'tags-module-template.html',
          controller: function($scope, $state) {
            const tags_model = [
              {
                ticker: 'AAPL',
                tags : [{ id: 1, term: 'iPhone 7' }, { id: 2, term: 'iPhone 8' }, { id: 3, term: 'Tim Cook' }]
              },
              {
                ticker: 'GOOG',
                tags : [{ id: 4, term: 'Pixel' }, { id: 5, term: 'Pixel XL' }, { id: 6, term: 'Chrome Book' }]
              },
              {
                ticker: 'TWTR',
                tags : [{ id: 7, term: 'tweet' }, { id: 8, term: 'retweet' }, { id: 9, term: 'moments' }]
              }
            ];
            
            function matchTags(ticker, model) {
              return model.filter(function(obj){
                if (obj.ticker === ticker) { return obj; }
              });
            }
            
            $scope.tags_model = matchTags($state.params.ticker.ticker, tags_model)[0];
            
            $scope.clickTag = function(tag) {
              $state.go('tags', { tag: tag });
            }
            
            console.log('Tags init', $state.params);
            // console.log(' Tags model', tags_model);
          }
        },
        'social@dashboard' : {
          templateUrl: 'social-module-template.html', 
          controller: function($state) {
            console.log('Social init', $state.params);
          }
        }
      }
    }

    $stateProvider
      .state(login)
      .state(dashboard);
});

Thoughts, would an architecture like this work? Basically login would navigate to a container state which will contain 2 components (dashboard and feed) each with their own internal states?

enter image description here

Community
  • 1
  • 1
Leon Gaban
  • 36,509
  • 115
  • 332
  • 529
  • I think this is not possible. Notify all, notify none or reload current state with/without notifiy would work. – lin Mar 16 '17 at 20:42

1 Answers1

1

I could resolve this issue depending on which state you're coming from. Based on the fact that you only want the feed to be loaded 'once' when dashboard is loaded, I'm checking the name of the previous state, and if it is not dashboard, only then I'll proceed with executing the rest of the controller code. Here is the plunker. Note that this is not very scalable approach if more states are added and if someone else has a better approach, I'd really like to see that.

I changed the controller code as follows:

feed.component('feedModule', {
  templateUrl: 'feed-module-template.html',
  controller: function($scope, $state) {
    var previousState = $state.params.previousState.name;
    if(previousState !== 'dashboard') {
      console.log('Feed init (only once)', $state.params); //do whatever u want here
    }
  }
});

I'm passing around previous state as params to other states like this:

controller: function($state) {
  this.login = function() {
    $state.go('dashboard', {previousState : { name : $state.current.name }})
  }
}

Look at the full plunker here to see if this helps your case!

clever_bassi
  • 2,392
  • 2
  • 24
  • 43
  • Thank you, yes that did work! I also got to the same conclusion that I needed another $state after the login. However now I'm facing a new issue, would you mind a look see here? Worth `200` points :) http://stackoverflow.com/questions/42865321/how-to-pass-state-variable-into-2-other-sibling-states – Leon Gaban Mar 20 '17 at 19:17
  • sure I'll take a look at it today. – clever_bassi Mar 20 '17 at 23:29