如何将$ state变量传递给另外两个同级$状态?

时间:2017-03-17 19:02:42

标签: javascript angularjs routing angular-ui-router state-management

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

架构:

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

目标:

tags需要进行通信并将标记对象发送到viewHeadersocialMedia个州。

预期:

登录之后,选择标签列表中的按钮应该将tag发送到 ViewHeader SocialMedia 状态/组件

结果:

登录之后,选择标签中的按钮并转到$状态dashboard ViewHeader SocialMedia 刷新但视图模型变量{{ term }}不会使用任一组件中的相应标记进行更新。

enter image description here

设计说明:

我试图用各种状态,组件,兄弟组件和视图来解决的问题是,当任何状态发生变化时,应用程序中的每个组件都会刷新/重新启动。 $state.go('dashboard'...

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

IE:当我选择 Ticker 标记时,我不希望每次都刷新 Feed 组件。但是,用户应该可以在 Feed 组件中执行操作,它将更新所有其他组件。

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

PS:开始使用ui-router了解状态管理,以消除对$ rootScope的依赖。到目前为止,我的真实应用程序更加稳定,但是每个组件都刷新/重新启动,这是一个烦人的功能。

enter image description here

在下面的屏幕截图中,我可以清楚地看到正确的tag正在传递到正确的$状态,但{{ term }}却未更新。

enter image description here

enter image description here

代码段(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>加载标记状态的原因是到目前为止我唯一能够初始化标记模块并显示标记列表中的标记列表。< / p>

代码组件控制器:

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 });
    }
 }

^&lt; --- above允许标签状态加载标签组件元素并根据股票行情状态连接标签列表

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 });
}

socialMedia controller:

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之后,注意到了这一点。看起来仪表板组件正在重新呈现以代替标签组件一瞬间:

enter image description here

已更新,通过将{ refresh: true }添加到标记中的$ state.go来解决此问题。但请注意,这仍然无法解决我的原始任务,这会阻止feed.component刷新。因此最终将使用服务。

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

enter image description here

3 个答案:

答案 0 :(得分:2)

我已更新你的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
  })

})

答案 1 :(得分:2)

我更新了你的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. 

这类似于last问题中发生的问题。

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

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

希望这有帮助!

更新

我更新了plunker here。我评论了这一行:

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

默认情况下,每当我们进入仪表板状态时,都会将自动收报机设置为苹果。我现在也将ticker和tag对象传递给视图和社交状态。如果你看一下控制台,你就可以得到正确的值来标记这些状态的代码和代码。如果这对您有用,请告诉我。

您可以通过查看控制台日志来验证标记和自动收报机值是否已传递到视图和社交组件中。 这是一个片段: enter image description here

答案 2 :(得分:0)

发布此信息是因为这是解决此问题的正确方法,并正确构建应用程序:

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

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

enter image description here

<强>容器template.html

Request::input('id');

标签状态

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

状态导航到child.child状态:

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;