简体   繁体   English

AngularJS ui路由器ui-sref导致“未捕获的TypeError:无法读取未定义的属性'0'”错误

[英]AngularJS ui-router ui-sref causing “Uncaught TypeError: Cannot read property '0' of undefined” error

I have an angularJS component using ui-router with 2 simple route states. 我有一个使用ui-router和2个简单路由状态的angularJS组件。

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

In the details view I have a controller that fetches a PDF document, then changes the route state in the callback using $state.go('pdf'); details视图中,我有一个控制器,该控制器获取PDF文档,然后使用$state.go('pdf');更改回调中的路由状态$state.go('pdf');

In the pdf view I have a ui-sref link going back to the details view: 在pdf视图中,我有一个ui-sref链接,可返回到详细信息视图:

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

Intermittently, when I press the Back to Details button, it throws an error from page.js and does not change the route state. 间歇性地,当我按下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 

Looking up the error source I get: (page.js: 208) 查找错误源:(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];
  }

The url and view stay at /viewpdf . 网址和视图位于/viewpdf If I wait a couple seconds and hit the back button again, it will work correctly. 如果我等了几秒钟然后再次按下返回按钮,它将可以正常工作。

What is causing this behavior, and how do I fix it? 是什么导致此现象,如何解决?

Edit I should clarify, when I refer to the back button, I am referring to the Back to Details button in the /viewpdf view, not the browser back button. 编辑我应该澄清一下,当我提到“后退”按钮时,我指的是/viewpdf视图中的“ 返回详细信息”按钮,而不是浏览器的“后退”按钮。 The browser back button does not exhibit the bug. 浏览器的后退按钮没有出现该错误。

This may get it working: 这可能使其工作:

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

reload Docs: reload文档:

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

You may also want to add a .then() to check if your pdf state is still loading when changing back to details state: 您可能还想添加.then()以在更改回details状态时检查pdf状态是否仍在加载:

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

then() Docs: then()文件:

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

Update: 更新:

If other nav buttons are placed within the state's component this section of the Docs may be of use. 如果在该州的组件中放置了其他导航按钮,则该文档的这一部分可能有用。

https://github.com/angular-ui/ui-router/wiki#user-content-view-load-events 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
  });

Within this listener you could do something like $scope.loaded = true with ng-disabled for nav buttons. 在此侦听器中,您可以执行类似$scope.loaded = true并为导航按钮ng-disabled

This test code configures a directive for a nav control along with disabling it until the view's DOM is loaded: 此测试代码为nav控件配置了一个指令,并禁用它,直到加载视图的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' });
  })
;

using html: 使用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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM