【问题标题】:AngularJS ui-router ui-sref causing "Uncaught TypeError: Cannot read property '0' of undefined" errorAngularJS ui-router ui-sref 导致“Uncaught TypeError: Cannot read property '0' of undefined”错误
【发布时间】:2018-08-10 16:35:55
【问题描述】:

我有一个使用 ui-router 的 angularJS 组件,它有 2 个简单的路由状态。

export default function Routes($stateProvider, $urlRouterProvider, $locationProvider) {
    $stateProvider
        .state('details', {
          url: '/',
          template: '<div>...</div>'
        })
        .state('pdf', {
          url: '/viewpdf',
          template: '<pdf-viewer></pdf-viewer>'
        });

    $urlRouterProvider.otherwise(function ($injector, $location) {
        var $state = $injector.get("$state");
        $state.go("details");
    });
}

details 视图中,我有一个控制器,它获取 PDF 文档,然后使用 $state.go('pdf'); 在回调中更改路由状态

在 pdf 视图中,我有一个 ui-sref 链接可以返回到详细信息视图:

<a ui-sref="details">Back to Details</a>

间歇性地,当我按下 Back to Details 按钮时,它会从 page.js 中抛出一个错误并且不会更改路由状态。

Uncaught TypeError: Cannot read property '0' of undefined
    at new Context (page.js:208)
    at Function.page.replace (page.js:154)
    at onpopstate (page.js:347)
    at B (history.min.js:21)
    at history.min.js:22
Context @ page.js:208
page.replace @ page.js:154
onpopstate @ page.js:347
B @ history.min.js:21
(anonymous) @ history.min.js:22

查找我得到的错误源:(page.js: 208)

/**
   * Initialize a new "request" `Context`
   * with the given `path` and optional initial `state`.
   *
   * @param {String} path
   * @param {Object} state
   * @api public
   */

function Context(path, state) {
    /* ERROR STACK ENDS ON THIS LINE */
    if ('/' == path[0] && 0 != path.indexOf(base)) path = base + path;
    /* END */
    var i = path.indexOf('?');

    this.canonicalPath = path;
    this.path = path.replace(base, '') || '/';

    this.title = document.title;
    this.state = state || {};
    this.state.path = path;
    this.querystring = ~i ? path.slice(i + 1) : '';
    this.pathname = ~i ? path.slice(0, i) : path;
    this.params = [];

    // fragment
    this.hash = '';
    if (!~this.path.indexOf('#')) return;
    var parts = this.path.split('#');
    this.path = parts[0];
    this.hash = parts[1] || '';
    this.querystring = this.querystring.split('#')[0];
  }

url 和视图保持在/viewpdf。如果我等待几秒钟,然后再次点击返回按钮,它将正常工作。

是什么导致了这种行为,我该如何解决?

编辑 我应该澄清一下,当我提到后退按钮时,我指的是/viewpdf 视图中的 Back to Details 按钮,而不是浏览器的后退按钮。浏览器后退按钮没有出现该错误。

【问题讨论】:

  • 几个问题:1)什么是page.js? 2) 你为什么不直接使用$urlRouterProvider.otherwise('details');,因为你没有在其他功能中使用任何高级功能?
  • 我没有显式添加page.js,它看起来像是ui-router的依赖。添加了 else 回调以解决其他一些路由问题(我现在不记得是哪个了?)。这是问题的简化版本,而不是整个应用程序。
  • 另外,我的理解是ui-sref 应该以otherwise 不发挥作用的方式设置路由状态。后退按钮简单地加载其他状态是不正确的。

标签: javascript angularjs angular-ui-router page.js


【解决方案1】:

这可能会让它工作:

$state.go('state',{},{
    reload: true
});

reload文档:

https://ui-router.github.io/ng1/docs/latest/interfaces/transition.transitionoptions.html#reload

您可能还想添加一个.then() 以检查在更改回details 状态时您的pdf 状态是否仍在加载:

$state.go(..
    .then(
        onfulfilled,
        onrejected
    );

then()文档:

https://ui-router.github.io/ng1/docs/latest/interfaces/state.transitionpromise.html#then

更新:

如果其他导航按钮放置在状态组件中,则文档的这一部分可能会有所帮助。

https://github.com/angular-ui/ui-router/wiki#user-content-view-load-events

$rootScope.$on('$viewContentLoaded',
  function(event, viewConfig){
      // Access to all the view config properties.
      // and one special property 'targetView'
      // viewConfig.targetView
  });

在此侦听器中,您可以使用ng-disabled 为导航按钮执行类似$scope.loaded = true 的操作。

此测试代码为导航控件配置指令,并在加载视图的 DOM 之前禁用它:

angular.module('app',['ui.router'])
  .component('componentHome', {
    template: '<div>Home Page Contents...</div>',
    controller: ['$scope','$state','$rootScope',function($scope,$state,$rootScope){
      $scope.loaded = false;
      $rootScope.$on('$viewContentLoaded',
      function(event, viewConfig){
          $scope.loaded = true;
      });
    }]
  })
  .component('componentA', {
    template: '<div><go></go></div>',
    controller: ['$scope','$state','$rootScope',function($scope,$state,$rootScope){
      $scope.loaded = false;
      $rootScope.$on('$viewContentLoaded',
      function(event, viewConfig){
          $scope.loaded = true;
      });
      $scope.stateName = 'b';
      $scope.stateLabel = 'B';
    }]
  })
  .component('componentB', {
    template: '<div><go></go></div>',
    controller: ['$scope','$state','$rootScope',function($scope,$state,$rootScope){
      $scope.loaded = false;
      $rootScope.$on('$viewContentLoaded',
      function(event, viewConfig){
          $scope.loaded = true;
      });
      $scope.stateName = 'a';
      $scope.stateLabel = 'A';
    }]
  })
  .directive('go',['$state',function($state){
    return {
      restrict: 'E',
      template: '<button ng-disabled="!loaded" state="stateName">Go to Page {{ stateLabel }}</button>',
      link: function(scope,element){
        element.on('click',function(e){
          $state.go(scope.stateName,{},{
            reload: true
          }).then(
            function(){
              // fulfilled
            },
            function(){
              // rejected
            }
          );
        });
      }
    };
  }])
  .config(function($stateProvider){
    $stateProvider.state('/',{ url: '/', component: 'componentHome' });
    $stateProvider.state('a',{ url: '/a', component: 'componentA' });
    $stateProvider.state('b',{ url: '/b', component: 'componentB' });
  })
;

使用html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="jquery.js"></script>
    <script src="angular.js"></script>
    <script src="angular-ui-router.min.js"></script>
    <style>
      .active{ border: 1px dashed red; }
    </style>
  </head>
  <body ng-app="app">
      <a ui-sref="/"  ui-sref-active="active">Home Page</a>
      <a ui-sref="a" ui-sref-active="active">Page A</a>
      <a ui-sref="b" ui-sref-active="active">Page B</a>
      <div>
        <ui-view></ui-view>
      </div>
    <script src="app.js"></script>
  </body>
</html>

【讨论】:

  • 我是否需要将 ui-sref 更改为单击处​​理程序调用以使用 $state.go 作为后退按钮?
  • @mhatch 取决于您的实施。我用一些额外的文档和测试代码更新了答案。
猜你喜欢
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 2019-02-12
相关资源
最近更新 更多