如何将 $state 变量传递给其他 2 个同级 $states?

How to pass $state variable into 2 other sibling $states?

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

架构:

$login -> $container(包含$dashboard$feed),dashboard包含:$tickers$tags , $viewHeader$socialMedia 个组件。

目标:

tags 需要通信并将标记对象发送到 viewHeadersocialMedia 状态。

预计:

登录 之后,select 点击标签列表中的按钮应该将 tag 发送到 ViewHeader社交媒体 states/components.

结果:

登录 之后,select 在标签中点击一个按钮并转到 $state dashboard ViewHeader 的 $states SocialMedia 刷新,但视图模型变量 {{ term }} 未使用任一组件中的相应标记进行更新。

设计说明:

我试图通过混合使用状态、组件、同级组件和视图来解决的问题是,当任何状态发生变化时,应用程序中的每个组件总是 refreshes/re-onInit。 $state.go('dashboard'...

这并不理想,我想要的是确保只有需要刷新的组件才刷新。

IE:当我 select TickerTag 我不想要 Feed 每次都要刷新的组件。但是,用户应该能够在 Feed 组件中执行操作,它将更新所有其他组件。

这就是为什么我创建了一个 container 状态来保存 dashboardfeed 状态的原因。最初我的所有内容都处于 dashboard 状态,任何时候 $state.go('dashboard' 发生 feed 组件也会刷新。如果有更好的办法解决这个问题lmk! :)

PS:开始使用 ui-router 学习状态管理,以消除对 $rootScope 的依赖。到目前为止,我的真实应用程序要稳定得多,但是每个组件都有令人讨厌的功能 refreshes/re-onInits.


在下面的屏幕截图中,我可以清楚地看到正确的 tag 被传递到正确的 $states,但是 {{ term }} 没有更新。

代码片段(Plnkr 中的完整代码)

app.container.html(容器状态)

<div>
    <dashboard-module></dashboard-module>
    <feed-module></feed-module>
    <!--<div ui-view="dashboard"></div>-->
    <!--<div ui-view="feed"></div>-->
</div>

dashboard.html(仪表板状态)

<div class="jumbotron text-center">
    <h1>The Dashboard</h1>
</div>

<div class="row">
  <tickers-module></tickers-module>

  <!-- Tags component goes here -->
  <div ui-view></div>

  <view-module></view-module>

  <social-module></social-module>
</div>

^ 我使用上面的 <div ui-view> 来加载标签状态的原因是,到目前为止,这是我可以初始化标签模块并显示代码组件中的标签列表的唯一方法。

代码组件控制器:

tickers.component('tickersModule', {
  templateUrl: 'tickers-module-template.html',
  controller: function($scope, $state) {
    console.log('Tickers component', $state.params);
    $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) {
      $state.go('tags', { ticker: ticker });
    }
 }

^ <--- 上面允许标签状态加载标签组件元素并连接标签列表,基于 ticker

的状态
var tags = angular.module('tags', ['ui.router'])
tags.config(function($stateProvider) {

  const tags = {
    parent: 'container',
    name: 'tags',
    url: '/tags',
    params: {
      ticker: {}
    },
    template: '<tags-module></tags-module>',
    controller: function($scope, $state) {
      console.log('Tags state', $state.params);
    }
  }

  $stateProvider.state(tags);
})
tags.component('tagsModule', {
  templateUrl: 'tags-module-template.html',
  controller: function($scope, $state) {
    console.log('Tags component', $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; }
      });
    }

    $state.params.ticker = $state.params.ticker || {};
    $scope.tags_model = matchTags($state.params.ticker.ticker, tags_model)[0];

    $scope.clickTag = function(tag) {
      console.log(' Tag clicked', $state);
      $state.go('dashboard', { tag: tag });
    }
  }
});

标签列表中的点击功能:

$scope.clickTag = function(tag) {
  console.log(' Tag clicked', $state);
  $state.go('dashboard', { tag: tag });
}

社交媒体控制器:

social.component('socialModule', {
  templateUrl: 'social-module-template.html',
  controller: function($scope, $state) {
    console.log('Social component', $state.params);
    $scope.term = $state.params.tag.term;
  }
});

viewHeader 控制器:

view.component('viewModule', {
  templateUrl: 'view-module-template.html',
  controller: function($scope, $state) {
    console.log('View component', $state.params);
    $scope.term = $state.params.tag.term;
  }
});

组件的奇怪加倍

刚刚注意到这一点,在点击标签并进入 social.component 内部之后。看起来仪表板组件正在重新呈现以代替标签组件一瞬间:


已更新,通过在标签中的 $state.go 中添加 { refresh: true } 解决了这里的问题。但是请注意,这仍然没有解决我最初的任务,即阻止 feed.component 刷新。所以最终会使用一个服务。

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

我已经更新了你的 plunker

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

解决方法相当简单。而不是使用 $state 在依赖注入中使用 $stateParams 这是一个单例,所以如果你像我在更新的 plunker 中那样引用它:

$scope.params = $stateParams

然后显示值

{{params.ticker.ticker}}

将以两种方式绑定到 $stateParams 并在您每次更改状态时相应地更新

---编辑---

我通过服务添加了另一个解决方案 https://plnkr.co/edit/oQNAHv7tAS8LR9njOUAX?p=preview

.service('awesomeTag', function($rootScope){
  var self = this;
  $rootScope.$on('$stateChangeSuccess', function(_event, _toState, toParams){
    self.tag = toParams.ticker.ticker
  })

})

我更新了你的 plunker here。您的代码中的问题在这里:

view.component('viewModule', {
  templateUrl: 'view-module-template.html',
  controller: function($scope, $state) {
    console.log('View component', $state.params);
    $scope.term = $state.params.tag.term; //culprit line
  }
});

您需要做的是使用 $stateParams 来检索参数。我在 viewModule 中修改了如下代码:

controller: function($scope, $stateParams) {
    console.log('View component', $stateParams);
    $scope.tickerObj = $stateParams;     
}

然后相应地更新 view-module-template.html 以使用 tickerObj,如下所示:

{{ tickerObj.ticker.ticker }}

社交模块也是如此。

了解其工作原理的简单示例如下:

$stateProvider.state('stateName', {
    url: '/stateName',
    controller: 'myCtrl',
    params: { //this can also be used to give default values for route params
        obj: null
    }
});

function myCtrl($stateParams) {
    console.log($stateParams);   //will display the obj parameter passed while transitioning to this state
}

$state.go('stateName', {obj:yourObj}); //passing obj as param to stateName state, this can be retrieved using $stateParams. 

这与您的 问题中发生的问题类似。

我注意到您的代码存在另一个问题。单击转推、时刻、推文等任何标签时,它会再次将行情代码更改为 "AAPL"。这是有意的行为吗? (如果不是,则发生这种情况是因为当您在单击股票代码后转换到仪表板状态时,所有模块都将被重新初始化。导致这种情况的行是

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

希望对您有所帮助!

更新:

我更新了 plunker here。我注释掉了这一行:

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

每次我们进入仪表板状态时,默认情况下将代码设置为苹果。我现在还将代码和标签对象传递给视图和社交状态。如果您查看控制台,您将能够获得正确的值来标记和这两种状态的代码。如果这对你有用,请告诉我。

您可以通过查看控制台日志来验证标签和代码值是否正在传递到视图和社交组件中。 这是一个片段:

张贴此内容是因为这是解决此问题并正确构建应用程序的正确方法:

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

这里我正确地使用了子状态和命名视图。

容器-template.html

<div>
  <div class="fl w100">
      <em>Container component module scope</em>  
  </div>

  <div ui-view="dashboard"></div>

  <div ui-view="feed" class="fl"></div>
</div>

标签状态

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

并且状态导航到 child.child 状态:

$scope.clickTicker = function(ticker) {
    $state.go('container.dashboard.tickers.tags', { ticker: ticker });
}