Plnkr: https://plnkr.co/edit/TrjrZ4vQlOjxyjp1prekQt<< a>

Esperada

Después de Iniciar sesión , seleccionar un Ticker debería mostrar la lista Etiquetas a la derecha de la lista Ticker en un área naranja llamada Ámbito de etiquetas.

Cómo debería verse la aplicación

enter image description here


Resultados

Al seleccionar un Ticker, se activará el estado de Etiquetas, sin embargo, la plantilla de Etiquetas reemplazará la vista de índice de nivel superior ui. En lugar de representar la plantilla de Etiquetas dentro de <div ui-view="tags@tickers"></div> en la plantilla Tickers.

Cómo se ve la aplicación

enter image description here

enter image description here

Arquitectura

Después de iniciar sesión, se le envía al estado container que tiene 2 vistas: dashboard y feed.

Siento que mi problema es que no estoy activando un dashboard state ni estoy activando un tickers state si es así, ¿cómo puedo hacerlo en mi arquitectura actual?


// 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>
0
Leon Gaban 23 mar. 2017 a las 17:58

2 respuestas

La mejor respuesta

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

¡Lo hice funcionar correctamente usando estados secundarios!

Necesario para nombrar estados así para que la aplicación sepa cuál es el padre:

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

Luego, al navegar por los estados, la convención de nomenclatura ayudó con especificidad

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

Y el uso adecuado de las vistas con nombre:

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

Código completo

// 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)
      });
}]);
1
Leon Gaban 23 mar. 2017 a las 20:11

Según el código que ha proporcionado, diría que ui-router está haciendo lo que debería. Tiene definido el estado tags para que se complete el ui-view sin nombre, y así es. Cuando hace clic en uno de los botones en el componente tickers, básicamente carga el estado tags en lugar del estado container.

Según el código que ha proporcionado, ha mezclado estados y vistas que deberían mostrarse cuando se carga un estado específico. Está intentando cargar un tags estado en un marcador de posición <div ui-view='tags'></div>, que representa un marcador de posición para tags vista , que es un vista para un estado específico que desea cargar. No es así como se supone que funciona ui-router.

Aquí hay un ejemplo de su código modificado. Puede ver aquí que he cargado dashboard, feed, tickers y tags vistas en su estado container. Aunque algunos de ellos están en plantillas separadas, todos se cargan bajo el mismo estado.

Como ya tiene un ejemplo de cómo se cargan los diferentes estados con login y container, aquí hay un ejemplo de su código modificado con un estado secundario. Cuando hace clic en el botón "Ir al estado privado", carga el estado container.private, que es un estado secundario del estado container. Como puede ver, el estado container.private tiene casi la misma estructura que el estado container. Cuando hace clic en el botón, cargará las vistas definidas para el estado container.private en sus correspondientes marcadores de posición.

No he eliminado todo el código innecesario, solo modifiqué lo que necesitaba. Lo siento por eso.

Por lo que puedo ver, tendrá que modificar su arquitectura para usar solo componentes y comunicarse entre los componentes con cualquiera de los servicios, algún tipo de sub biblioteca de pub o intentar usar $scope.$emit y $scope.$on si tiene una relación padre-hijo entre su controlador.

0
eminlala 23 mar. 2017 a las 17:35