如何将 $state 变量传递给其他 2 个同级 $states?
Plnkr:
设计说明:
我试图通过混合状态、组件、兄弟组件和视图来解决的问题是,当任何状态发生变化时,应用程序中的每个组件都会刷新/重新启动.$state.go('dashboard'...
这并不理想,我想要的是确保只有需要刷新的组件,刷新.
IE:当我选择 Ticker 或 Tag 时,我不希望 Feed 组件每次都刷新.但是,用户应该能够在 Feed 组件中执行操作,并且它将更新所有其他组件.
这就是为什么我创建了一个 container
状态来保存 dashboard
和 feed
状态.最初我的所有东西都处于 dashboard
状态,并且任何时候 $state.go('dashboard'
发生 feed
组件也会刷新.如果有是解决这个问题的更好方法lmk!:)
PS:开始学习使用 ui-router 进行状态管理,以消除对 $rootScope 的依赖.到目前为止,我的真实应用程序要稳定得多,但有一个烦人的功能,即每个组件都会刷新/重新启动.
<小时>在下面的屏幕截图中,我可以清楚地看到正确的 tag
被传递到正确的 $states 中,但是 {{ term }}
没有更新.
代码片段(Plnkr 中的完整代码)
app.container.html(容器状态)
<仪表板模块></仪表板模块><feed-module></feed-module><!--<div ui-view="dashboard"></div>--><!--<div ui-view="feed"></div>--></div>
dashboard.html(仪表板状态)
<div class="jumbotron text-center"><h1>仪表板</h1></div><div 类="行"><tickers-module></tickers-module><!-- 标签组件放在这里--><div ui-view></div><view-module></view-module><social-module></social-module></div>
^ 我使用上面的 <div ui-view>
加载标签状态的原因是,到目前为止,这是我可以初始化标签模块并显示标签的唯一方法来自股票代码组件的列表.
tickers 组件控制器:
tickers.component('tickersModule', {templateUrl: 'tickers-module-template.html',控制器:功能($范围,$状态){console.log('Tickers 组件', $state.params);$scope.tickers = [{ id: 1, 股票代码: 'AAPL' },{ id: 2, 股票代码: 'GOOG' },{ id:3,股票代码:'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) {常量标签 = {父:'容器',标签',网址:'/标签',参数:{代码:{}},模板:'<tags-module></tags-module>',控制器:功能($范围,$状态){console.log('标签状态', $state.params);}}$stateProvider.state(标签);})tags.component('tagsModule', {templateUrl: 'tags-module-template.html',控制器:功能($范围,$状态){console.log('标签组件', $state.params);常量标签模型= [{股票代码:'AAPL',标签: [{ id: 1, term: 'iPhone 7'}, { id: 2, term: 'iPhone 8'}, { id: 3, term: 'Tim Cook' }]},{股票代码:'GOOG',标签:[{ id: 4, term: 'Pixel' }, { id: 5, term: 'Pixel XL' }, { id: 6, term: 'Chrome Book' }]},{股票代码:'TWTR',标签:[{ id:7,term:'tweet'},{id:8,term:'retweet'},{id:9,term:'moments'}]}];功能匹配标签(股票代码,模型){返回模型过滤器(函数(obj){if (obj.ticker ===ticker) { 返回 obj;}});}$state.params.ticker = $state.params.ticker ||{};$scope.tags_model = matchTags($state.params.ticker.ticker, tags_model)[0];$scope.clickTag = 函数(标签){console.log('标签被点击', $state);$state.go('dashboard', { tag: tag });}}});
标签列表中的点击功能:
$scope.clickTag = function(tag) {console.log('标签被点击', $state);$state.go('dashboard', { tag: tag });}
社交媒体控制器:
social.component('socialModule', {templateUrl: '社会模块模板.html',控制器:功能($范围,$状态){console.log('社交组件', $state.params);$scope.term = $state.params.tag.term;}});
viewHeader 控制器:
view.component('viewModule', {templateUrl: 'view-module-template.html',控制器:功能($范围,$状态){console.log('查看组件', $state.params);$scope.term = $state.params.tag.term;}});
<小时>
奇怪的组件加倍
刚刚注意到这一点,在单击一个标签并闯入 social.component 之后.看起来仪表板组件正在重新渲染一瞬间代替标签组件:
<小时>更新,通过在标签中添加 { refresh: true }
到 $state.go 解决了这里的问题.但是请注意,这仍然没有解决我最初的任务,即阻止 feed.component 刷新.所以最终会使用服务.
解决方案 我已经更新了你的插件
https://plnkr.co/edit/ywyH7wOmR6loNiAkH9Yb?p=preview
解决方案相当简单.而不是使用 $state
在依赖注入中使用 $stateParams
这是一个单例,所以如果你像我在更新的 plunker 中那样引用它:
$scope.params = $stateParams
然后是显示值
{{params.ticker.ticker}}
将 2 路绑定到 $stateParams 并在每次更改状态时相应更新
---编辑---
我通过服务添加了另一个解决方案https://plnkr.co/edit/oQNAHv7tAS8LR9njOUAX?p=preview
.service('awesomeTag', function($rootScope){变种自我=这个;$rootScope.$on('$stateChangeSuccess', function(_event, _toState, toParams){self.tag = toParams.ticker.ticker})})
Plnkr: https://plnkr.co/edit/Brmcxd2LjGVJ6DXwuJtF?p=preview
Architecture:
$login
-> $container
(contains $dashboard
and $feed
), dashboard
contains: $tickers
, $tags
, $viewHeader
and $socialMedia
components.
Goal:
tags
needs to communicate and send a tag object into the viewHeader
and socialMedia
states.
Expected:
After Login, selecting a button in the Tags list should send that tag
into the ViewHeader and SocialMedia states/components.
Results:
After Login, selecting a button in the Tags and going to $state dashboard
the $states for the ViewHeader and SocialMedia refresh but the view model variable {{ term }}
does not update with the appropriate tag in either component.
Design explanation:
The problem I'm trying to solve with a mix of states, components, sibling components and views is that every component in the app always refreshes/re-onInit when any state changes. $state.go('dashboard'...
This is not ideal, what I want is to make sure that only the components that need to refresh, refresh.
IE: When I select a Ticker or a Tag I do NOT want the Feed component to refresh every single time. However the user should be able to take an action in the Feed component and it will update all the others.
This is why I created a container
state to hold both the dashboard
and feed
states. Originally I had everything in the dashboard
state, and anytime $state.go('dashboard'
happened the feed
component would also refresh. If there is a better way to solve this issue lmk! :)
PS: Started learning about state management using ui-router to remove the reliance on $rootScope. So far my real app is much more stable, however has the annoying feature that every component refreshes/re-onInits.
In this screenshot below I can clearly see that the correct tag
is being passed into the correct $states, but yet {{ term }}
does not update.
Code snippets (Full code in Plnkr)
app.container.html (container state)
<div>
<dashboard-module></dashboard-module>
<feed-module></feed-module>
<!--<div ui-view="dashboard"></div>-->
<!--<div ui-view="feed"></div>-->
</div>
dashboard.html (dashboard state)
<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>
^ The reason I'm using a <div ui-view>
above to load the tags state is that so far has been the only way I could initialize the tags module and show the tags list from the tickers component.
tickers component controller:
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 });
}
}
^ That <--- above allows the tags state to load the tags component element and wire up the tags list, based on the state of 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 });
}
}
});
The click function in the Tags list:
$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 controller:
view.component('viewModule', {
templateUrl: 'view-module-template.html',
controller: function($scope, $state) {
console.log('View component', $state.params);
$scope.term = $state.params.tag.term;
}
});
Strange doubling up of components
Just noticed this, after clicking on a tag and breaking inside of the social.component. It looks like the dashboard component is being re-rendering in place of the tags component for a split second:
Updated, solved the issue here by adding { refresh: true }
to $state.go in tags. Note however this still did not solve my original mission, which was preventing the feed.component from refreshing. So will end up using a service.
https://plnkr.co/edit/R0iwJznOgEwOL7AtU5wP?p=preview
解决方案I've updated your plunker
https://plnkr.co/edit/ywyH7wOmR6loNiAkH9Yb?p=preview
The solution is fairly simple. Instead of using $state
use $stateParams
in the dependency injection which is a singleton so if you reference it like I did in the updated plunker:
$scope.params = $stateParams
then the display value
{{params.ticker.ticker}}
will be 2 way bound to the $stateParams and update accordingly every time you change state
---edit---
I've added another solution through service 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
})
})
相关文章