导航到状态将索引 ui-view 替换为状态的组件,而不是父模板中的命名 ui-view

Navigating to state replaces the index ui-view with state's component, instead of named ui-view inside of parent's template

Plnkr: https://plnkr.co/edit/TrjrZ4vQlOjxyjc1mKQt?p=preview

预期

登录 选择代码后,标签列表应该会显示在代码列表右侧的名为标签范围的橙色区域中。

应用应该是什么样子


结果

选择代码将激活标签状态,但标签模板将替换顶级索引 ui-视图。而不是在 Tickers 模板中的 <div ui-view="tags@tickers"></div> 内呈现 Tags 模板。

应用的外观

建筑

登录后,您将进入 container 状态,其中有 2 个视图:dashboardfeed

我觉得我的问题是我没有激活 dashboard state 也没有激活 tickers state 如果是的话,我该如何在我当前的架构中做到这一点?


// Container module
////////////////////////////////////////////////////////////////////////////////
var container = angular.module('container', [ 'ui.router' ])
  container.config(function($stateProvider) {
    const container = {
      name: 'container',
      url: '/container',
      views: {
        '': {
          templateUrl: 'container-template.html',
          controller: function($scope) {
            console.log('CONTAINER view $state');
          }
        },
        'dashboard@container': {
          templateUrl: 'dashboard-template.html',
          controller: function($scope, $state) {
            console.log('DASHBOARD view $state', $state);
          }
        },
        'feed@container': {
          templateUrl: 'feed-template.html',
          controller: function($scope) {
            console.log('FEED view $state');
          }
        }
      }
    }
    
    $stateProvider.state(container);
  });
仪表板模板
<div class="dashboard-state">
  <div class="fl w100">
    <em>Dashbaord scope</em>  
  </div>
  
  <!--<div ui-view="tickers"></div>-->
  <tickers-module></tickers-module>
</div>
代码组件
tickers.component('tickersModule', {
  templateUrl: 'tickers-template.html',
  controller: function($scope, $state) {
    console.log('TICKERS component');
    $scope.tickers = [
      { id: 1, ticker: 'AAPL' },
      { id: 2, ticker: 'GOOG' },
      { id: 3, ticker: 'TWTR' }
    ];
    
    $scope.clickTicker = function(ticker) {
      console.log(' Ticker clicked!', $state)
      $state.go('tags', { ticker: ticker }); // <~~~~ Action to go to Tags
    }
  }
});
代码模板
<div class="tickers-state">
  <div class="fl w100">
    <em>Tickers scope</em>    
  </div>

  <div class="tickers-panel">
    <div class="tickers-list">
      <ul>
        <li ng-repeat="ticker in tickers" class="fl">
          <button ng-click="clickTicker(ticker)">{{ ticker.ticker }}</button>
        </li>
      </ul>      
    </div>
  </div>
  
  <div ui-view="tags@tickers"></div>
  <!--<tags-module></tags-module>-->
  
</div>

根据您提供的代码,我会说 ui-router 正在做它应该做的事情。您定义了 tags 状态,因此它将填充未命名的 ui-view,它确实如此。当您单击 tickers 组件中的其中一个按钮时,它基本上会加载 tags 状态而不是 container 状态。

根据您提供的代码,您混淆了加载特定状态时应显示的状态和视图。您正在尝试在 <div ui-view='tags'></div> 占位符中加载 tags state,它表示 tags view[=52 的占位符=],这是您要加载的特定 状态视图。这不是 ui-router 应该工作的方式。

这是您修改后的代码的 example。您可以在这里看到,我已经在您的 container 状态下加载了 dashboardfeedtickerstags 视图。虽然有些在单独的模板里,但是都是在同一个状态下加载的

因为您已经有一个示例,如何使用 logincontainer 状态加载不同的状态,这里是您修改后的代码的 example 子状态。当您单击 "Go To Private State" 按钮时,它会加载 container.private 状态,它是 container 状态的子状态。如您所见,container.private 状态与 container 状态几乎具有相同的结构。当您单击该按钮时,它将在相应的占位符中加载为 container.private 状态定义的视图。

我没有删除所有不需要的代码,只是修改了我需要的。对不起。

据我所知,您将不得不修改您的体系结构以仅使用组件并在组件之间与任一服务进行通信,某种发布子库或尝试使用 $scope.$emit$scope.$on 如果你的控制器之间有父子关系。

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

通过正确使用子状态让它工作!

需要像这样命名状态,让应用知道父级是什么:

const dashboard = {
    name: 'container.dashboard',
    views: {
        'dashboard': {
            template: '<dashboard-module></dashboard-module>'
        },
        'feed': {
          templateUrl: 'feed-template.html',
          controller: function($scope) {
            console.log('FEED STATE');
          }
        }
    }
}

然后在导航状态时,命名约定有助于明确

$scope.clickTicker = function(ticker) {
  console.log(' >>> ticker view state', ticker)
  $state.go('container.dashboard.tickers.tagslist', { ticker: ticker });
}

正确使用命名视图:

const tags = {
  name: 'container.dashboard.tickers.tagslist',
  url: '/tags',
  params: {
    ticker: {}
  },
  views: {
    'tags' : {

完整代码

// Container module
////////////////////////////////////////////////////////////////////////////////
var container = angular.module('container', [ 'ui.router' ])
  container.config(function($stateProvider) {

    const container = {
      name: 'container',
      url: '/container',
      templateUrl: 'container-template.html',
      controller: function($scope, $state) {
        console.log('CONTAINER STATE');
        // $state.go('dashboard', {});
      }
    }

    const dashboard = {
        name: 'container.dashboard',
        // deepStateRedirect: true,
        // sticky: true,
        views: {
            'dashboard': {
                template: '<dashboard-module></dashboard-module>'
            },
            'feed': {
              templateUrl: 'feed-template.html',
              controller: function($scope) {
                console.log('FEED STATE');
              }
            }
        }
    }

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

// Dashboard module
////////////////////////////////////////////////////////////////////////////////
var dashboard = angular.module('dashboard', [ 'ui.router' ])

    dashboard.config(function($stateProvider) {
      const dash_default = {
        name: 'container.dashboard.default',
        url: '/dashboard',
        template: '<tickers-module></tickers-module>',
        controller: function() {
          console.log(' DASHBOARD.DEFAULT STATE')
        }
      }
      $stateProvider.state(dash_default);
    })

    dashboard.component('dashboardModule', {
    templateUrl: 'dashboard-template.html',
    controller: function($scope, $state) {
      console.log('DASHBOARD component');
    }
  });

// Tickers module
////////////////////////////////////////////////////////////////////////////////
var tickers = angular.module('tickers', ['ui.router'])

  tickers.config(function($stateProvider) {

    const tickers = {
      // parent: 'dashboard',
      name: 'container.dashboard.tickers',
      url: '/tickers',
      params: {
        ticker: {}
      },
      views: {
        '': {
          templateUrl: 'tickers-template.html',
          controller: function($scope, $state) {
            console.log(' TICKERS STATE', $state);

            $scope.tickers = [
              { id: 1, ticker: 'AAPL' },
              { id: 2, ticker: 'GOOG' },
              { id: 3, ticker: 'TWTR' }
            ];

            // $state.go('tags', { ticker: $scope.tickers[0] });

            $scope.clickTicker = function(ticker) {
              console.log(' >>> ticker view state', ticker)
              $state.go('container.dashboard.tickers.tagslist', { ticker: ticker });
            }
          }
        }
      }
    }

    $stateProvider.state(tickers);
  })
  tickers.component('tickersModule', {
    templateUrl: 'tickers-template.html',
    controller: function($scope, $state) {
      console.log('TICKERS component');
      // $scope.tickers = [
      //   { id: 1, ticker: 'AAPL' },
      //   { id: 2, ticker: 'GOOG' },
      //   { id: 3, ticker: 'TWTR' }
      // ];

      // $scope.clickTicker = function(ticker) {
      //   console.log(' Ticker clicked!', $state)
      //   $state.go('tags.list', { ticker: ticker });
      // }
    }
  });

// Tags module
////////////////////////////////////////////////////////////////////////////////
var tags = angular.module('tags', ['ui.router'])
  tags.config(function($stateProvider) {

    const oldtags = {
      name: 'tags',
      url: '/tags',
      params: {
        ticker: {},
        tag: {}
      },
      // parent: 'tickers',
      views: {
        '': {
          templateUrl: 'tags-template.html',
          controller: function($scope, $state) {
            console.log('Tags view $state', $state.params);
            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];

            console.log(' $scope.tags_model', $scope.tags_model)

            $scope.clickTag = function(tag) {
              $state.go('tags', { tag: tag });
            }

            console.log('Tags init', $state.params);
          }
        },
        'list@tags': {

        },
        'view@tags': {
          template: '<view-module ticker="$ctrl.ticker"></view-module>',
          controller: function($scope, $state) {
            console.log('VIEWS view $state');
            $scope.term = $state.params.tag.term;
          }
        },
        'chart@tags': {
          templateUrl: 'chart-template.html',
          controller: function($scope, $state) {
            console.log('CHART view $state');
            $scope.term = $state.params.tag.term;
          }
        },
        'social@tags': {
          templateUrl: 'social-template.html',
          controller: function($scope, $state) {
            console.log('SOCIAL view $state');
            $scope.term = $state.params.tag.term;
          }
        }
      }
    }

    const tags = {
      name: 'container.dashboard.tickers.tagslist',
      url: '/tags',
      params: {
        ticker: {}
      },
      views: {
        'tags' : {
          templateUrl: 'tags-list.html',
          controller: function($scope, $state) {
            console.log(' tags-list controller', $state)
            $scope.ticker = $state.params.ticker;

            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];

            console.log(' $scope.tags_model', $scope.tags_model)

            $scope.clickTag = function(tag) {
              $state.go('tags', { tag: tag });
            }
          }
        },
        'view@tags': {
          template: '<view-module ticker="$ctrl.ticker"></view-module>',
          controller: function($scope, $state) {
            console.log('VIEWS view $state');
            $scope.term = $state.params.tag.term;
          }
        }
      }
    }

    $stateProvider
      .state(tags);
      // .state(tagslist);
  })
  tags.component('tagsModule', {
    templateUrl: 'tags-template.html',
    controller: function($scope, $state) {
      console.log('TAGS component', $state.params);
    }
  });

// ViewHeader module
////////////////////////////////////////////////////////////////////////////////
var view = angular.module('view', ['ui.router'])
  view.component('viewModule', {
    templateUrl: 'view-template.html',
    bindings: {
      ticker: '<'
    },
    controller: function($scope, $state) {
      console.log('VIEW component', $state.params);
      $scope.ticker = this.ticker;
      $scope.term = $state.params.tag.term;
    }
  });

// Chart module
////////////////////////////////////////////////////////////////////////////////
var chart = angular.module('chart', ['ui.router'])
  chart.component('chartModule', {
    templateUrl: 'chart-template.html',
    controller: function($scope, $state) {
      console.log('CHART component', $state.params);
      $scope.term = $state.params.tag.term;
    }
  });

// Social module
////////////////////////////////////////////////////////////////////////////////
var social = angular.module('social', ['ui.router'])
  social.component('socialModule', {
    templateUrl: 'social-template.html',
    controller: function($scope, $state) {
      console.log('SOCIAL component', $state.params);
      $scope.term = $state.params.tag.term;
    }
  });

// TickersApp module
////////////////////////////////////////////////////////////////////////////////
var tickersApp = angular.module('tickersApp', 
  ['ui.router',
   'container',
   'dashboard',
   'tickers',
   'tags',
   'view',
   'chart',
   'social']);

tickersApp.config(function($stateProvider, $urlRouterProvider) {

  $urlRouterProvider.otherwise('/login');

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

  $stateProvider
    .state(login);
})
.run(['$rootScope', '$location', '$state',
function($rootScope, $location, $state) {
    // $rootScope.$on("$stateChangeError", console.log.bind(console));
    $rootScope.$on('$stateChangeStart',
      function(event, toState, toParams, fromState, fromParams, options) {
          // console.log(' ')
          // console.log('toState', toState)
          // console.log('state.current.name', $state.current.name)
          // console.log('toParams', toParams)
          // console.log('fromState', fromState)
          // console.log('fromParams', fromParams)
          // console.log('options', options)
      });

    $rootScope.$on('$stateChangeSuccess', 
      function(event, toState, toParams, fromState, fromParams){
        console.log('state.current.name', $state.current.name)
      })

    $rootScope.$on('$stateChangeError', 
      function(event, toState, toParams, fromState, fromParams, error){
        console.error('ERROR toState', toState)
        console.error('ERROR fromState', fromState)
      });

    $rootScope.$on('$stateNotFound', 
      function(event, unfoundState, fromState, fromParams){ 
          console.log('unfoundState.to', unfoundState.to); // "lazy.state"
          // console.log('unfoundState.toParams', unfoundState.toParams); // {a:1, b:2}
          // console.log('unfoundState.options', unfoundState.options); // {inherit:false} + default options
      });

    $rootScope.$on('$viewContentLoaded', 
      function(event){
        // console.log('viewContentLoaded', event)
      });
}]);