Comment passer $ state variable dans 2 autres états de frères et sœurs?

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

Architecture:

$login -> $container (contient $dashboard et $feed ), le dashboard contient: $tickers , $tags , $viewHeader et $socialMedia .

Objectif:

tags doivent communiquer et envoyer un objet tag dans les viewHeader et socialMedia .

Attendu:

Après la connexion , sélectionner un bouton dans la liste des balises doit envoyer cette tag dans les états / composants ViewHeader et SocialMedia .

Résultats:

Après la connexion , en sélectionnant un bouton dans les balises et en allant sur le dashboard $ state les états $ pour le rafraichissement ViewHeader et SocialMedia mais la variable modèle {{ term }} ne se met pas à jour avec la balise appropriée dans l'un ou l'autre composant.

Entrez la description de l'image ici

Explication de conception:

Le problème que j'essaie de résoudre avec un mélange d'états, de composants, de composants et de vues de frères et sœurs est que chaque composant de l'application est toujours actualisé / réinitialisé lorsque l'état change. $state.go('dashboard'...

Ce n'est pas idéal, ce que je veux, c'est de s'assurer que seuls les composants qui doivent être rafraîchis, rafraîchissent.

IE: lorsque je sélectionne un Ticker ou une étiquette, je ne souhaite PAS que le composant Feed soit actualisé toutes les fois. Toutefois, l'utilisateur devrait pouvoir prendre une action dans le composant Feed et il mettra à jour tous les autres.

C'est pourquoi j'ai créé un état de container pour tenir à la fois le dashboard et feed états d' feed . À l'origine, j'avais tout dans l'état du dashboard et, à tout moment, $state.go('dashboard' est arrivé, le composant d' feed serait également actualisé. S'il y a un meilleur moyen de résoudre ce problème, lmk! 🙂

PS: a commencé à apprendre sur la gestion de l'état en utilisant ui-router pour supprimer la dépendance sur $ rootScope. Jusqu'à présent, ma véritable application est beaucoup plus stable, mais la fonctionnalité ennuyeuse est que chaque composant actualise / re-onInits.

Entrez la description de l'image ici


Dans cette capture d'écran ci-dessous, je peux clairement voir que la tag correcte est passée dans les états $ corrects, mais pourtant {{ term }} ne se met pas à jour.

Entrez la description de l'image ici

Entrez la description de l'image ici

Extraits de code (code complet dans Plnkr)

App.container.html (état du conteneur)

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

Dashboard.html (état du tableau de bord)

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

^ La raison pour laquelle j'utilise une <div ui-view> ci <div ui-view> dessus pour charger l'état des balises est que jusqu'à présent a été la seule façon d'initialiser le module tags et de montrer la liste des balises du composant tickers.

Contrôleur de composant tickers:

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

^ Cela <— ci-dessus permet à l'état des balises de charger l'élément composant des balises et de filer la liste des balises, en fonction de l'état du 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 }); } } }); 

La fonction de clic dans la liste des tags:

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

Contrôleur socialMedia:

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

Contrôleur 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; } }); 

Doublage étrange des composants

Il suffit de remarquer ceci, après avoir cliqué sur une étiquette et la rupture dans le social.component. Il semble que le composant du tableau de bord est en train de redistribuer à la place du composant tags pour une fraction de seconde:

Entrez la description de l'image ici


Mise à jour, résolu le problème ici en ajoutant { refresh: true } à $ state.go dans les tags. Notez cependant que cela ne résolut toujours pas ma mission initiale, ce qui empêchait le feed.component de se rafraîchir. Cela finira par utiliser un service.

Entrez la description de l'image ici

J'ai mis à jour votre plunker

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

La solution est assez simple. Au lieu d'utiliser $state use $stateParams dans l'injection de dépendance qui est un singleton, alors si vous le référez comme je l'ai fait dans le plunker mis à jour:

 $scope.params = $stateParams 

Puis la valeur d'affichage

 {{params.ticker.ticker}} 

Sera lié à 2 voies avec les $ stateParams et la mise à jour en conséquence chaque fois que vous modifiez l'état

—modifier—

J'ai ajouté une autre solution via le 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 }) }) 

J'ai mis à jour votre plunker ici . Le problème dans votre code était ici:

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

Ce que vous devez plutôt faire, c'est utiliser $ stateParams pour récupérer les paramètres. J'ai changé le code dans viewModule comme suit:

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

Et ensuite, a mis à jour le view-module-template.html pour utiliser tickerObj comme suit:

 {{ tickerObj.ticker.ticker }} 

Même chose pour le module social.

Un exemple simple pour comprendre comment cela fonctionne est le suivant:

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

Ceci est similaire au problème qui se passe dans votre dernière question.

J'ai remarqué un autre problème avec votre code. En cliquant sur l'une des étiquettes comme retweet, moments, tweet, il change le ticker à "AAPL" à nouveau. Ce comportement est-il prévu? (Si ce n'est pas le cas, cela se produit car lorsque vous passez à l'état du tableau de bord après avoir cliqué sur un ticker, tous les modules sont réinitialisés. La ligne qui provoque ceci est

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

J'espère que cela t'aides!

Mettre à jour:

J'ai mis à jour le plunker ici . J'ai commenté cette ligne:

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

Qui était par défaut fixer ticker à apple chaque fois que nous venions à l'état du tableau de bord. Je transmet également le code et l'objet de l'étiquette à la fois à la fois à l'état de la vue et à l'état social. Si vous regardez la console, vous pouvez obtenir les valeurs correctes pour les étiquettes et les tickers sur ces deux états. Faites-moi savoir si cela fonctionne pour vous.

Vous pouvez vérifier que les valeurs de l'étiquette et du ticker sont transmises à la vue et aux composants sociaux en regardant les journaux de la console. Voici un extrait: Entrez la description de l'image ici

En publiant ceci parce que c'est la bonne façon de résoudre ce problème, et correctement architecte l'application:

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

Ici, j'utilise correctement les états enfants et les vues nommées.

Entrez la description de l'image ici

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

Les tags indiquent

 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; 

Et la navigation d'état à children.child déclare:

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