如何设置强制路由参数

时间:2015-03-13 20:47:41

标签: angular-ui-router

我想制作一个带有强制参数的路线。如果没有,它应该落入

$urlRouterProvider.otherwise("/home");

当前路线:

function router($stateProvider) {
        $stateProvider.state("settings", {
            url: "^/settings/{id:int}",
            views: {
                main: {
                    controller: "SettingsController",
                    templateUrl: "settings.html"
                }
            }
        });
    }

目前以下两条路线均有效:

  1. http://myapp/settings //应该是无效路线
  2. http://myapp/settings/123
  3. 有什么想法吗?

4 个答案:

答案 0 :(得分:0)

使用state change start listener检查params是否通过:

  $rootScope.$on('$stateChangeStart',
                function (event, toState, toParams, fromState, fromParams) {
      if(toState.name==="settings")
      {
          event.preventDefault(); //stop state change
          if (toParams.id===undefined)
           $state.go("home");
          else
           $state.go(toState, toParams);

      }
  });

答案 1 :(得分:0)

以下解决方案适用于ui-router 1.0.0:

.config(($stateProvider, $transitionsProvider) => {

  //Define state
  $stateProvider.state('verifyEmail', {
    parent: 'portal',
    url: '/email/verify/:token/:optional',
    component: 'verifyEmail',
    params: {
      token: {
        type: 'string',
      },
      optional: {
        value: null,
        squash: true,
      },
    },
  });

  //Transition hooks
  $transitionsProvider.onBefore({
    to: 'verifyEmail',
  }, transition => {

    //Get params
    const params = transition.params();

    //Must have token param
    if (!params.token) {
      return transition.router.stateService.target('error', {
        type: 'page-not-found',
      });
    }
  });
 })

以上内容将强制:token参数,:optional参数可选。如果您尝试浏览到没有token参数的页面,它将无法转换并重定向到您的错误页面。但是,如果省略:optional参数,则会使用默认值(null)。

请记住在尾随的可选参数上使用squash: true,否则如果省略URL中的尾随/,您也会获得404。

注意:钩子是必需的,因为如果你使用尾部斜杠浏览到email/verify/,ui-router会认为token参数是一个空字符串。因此,您需要在转换挂钩中进行额外处理以捕获这些情况。

答案 2 :(得分:0)

在我的应用中,我必须为很多路线制作必需的参数。所以我需要一种可重复使用且干燥的方法来做到这一点。

我在应用中定义constants区域以访问全局代码。我也用于其他事情。

我在app配置时运行此notFoundHandler。这是为处理错误设置路由器状态。它正在设置此错误路由的其他路由。您可以为缺少必需参数的时间定义不同的路径,但对我们而言,这被定义为与404体验相同。

现在在app运行时我还定义了一个stateChangeErrorHandler,它将使用'required-param'字符串查找被拒绝的路由解析。

angular.module('app')
    .constant('constants', constants)
    .config(notFoundHandler)
    .run(stateChangeErrorHandler);

// use for a route resolve when a param is required
function requiredParam(paramName) {
    return ['$stateParams', '$q', function($stateParams, $q) {
        // note this is just a truthy check.  if you have a required param that could be 0 or false then additional logic would be necessary here
        if (!$stateParams[paramName]) {
            // $q.reject will trigger the $stateChangeError
            return $q.reject('required-param');
        }
    }];
}
    
var constants = {
    requiredParam: requiredParam,
    // define other constants or globals here that are used by your app
};

// define an error state, and redirect to it if no other route matches
notFoundHandler.$inject = ['$stateProvider', '$urlRouterProvider'];
function notFoundHandler($stateProvider, $urlRouterProvider) {
    $stateProvider
        //abstract state so that we can hold all our ingredient stuff here
        .state('404', {
            url: '/page-not-found',
            views: {
                '': {
                    templateUrl: "/app/error/error.tpl.html",
                }
            },
            resolve: {
                $title: function () { return 'Page Not Found'; }
            }
        });

    // redirect to 404 if no route found
    $urlRouterProvider.otherwise('/page-not-found');
}

// if an error happens in changing state go to the 404 page
stateChangeErrorHandler.$inject = ['$rootScope', '$state'];
function stateChangeErrorHandler($rootScope, $state) {
    $rootScope.$on('$stateChangeError', function(evt, toState, toParams, fromState, fromParams, error) {
        if (error && error === 'required-param') {
// need location: 'replace' here or back button won't work on error page
            $state.go('404', null, {
                location: 'replace'
            });
        }
    });
}

现在,在应用程序的其他地方,当我定义了一个路由时,我可以使它具有此路由解析所需的参数:

angular.module('app')
    .config(routeConfig);

routeConfig.$inject = ['$stateProvider', 'constants'];

function routeConfig($stateProvider, constants) {
    $stateProvider.state('app.myobject.edit', {
	    url: "/:id/edit",
	    views: {
		    '': {
		        template: 'sometemplate.html',
		        controller: 'SomeController',
		        controllerAs: 'vm',
		    }
	    },
	    resolve: {
		    $title: function() { return 'Edit MyObject'; },
// this makes the id param required
		    requiredParam: constants.requiredParam('id')
	    }
	});
}

答案 3 :(得分:0)

我想指出不应该访问/settings路径的任何问题,因为它不对应任何状态,除非你使用过继承状态(见下文)。

访问/settings/路径时会发生实际问题,因为它会将空字符串"")分配给{{ 1}}参数。

如果您没有使用继承状态

以下是问题中的solution以下问题:

  

访问id路径,当状态为url /state_name/

解决方案说明

它通过转换服务onBefore挂钩( UI路由器1.x 或更高版本)工作,这可以防止转换到的状态缺少必需的参数

为了声明某个状态的必需参数,我使用/state_name/:id哈希,如下所示:

data

然后在.state('settings', { url: '/settings/:id', data: { requiredParams: ['id'] } }); 中添加app.run挂钩:

onBefore

如果您使用了继承状态

您可以通过继承状态实现相同的逻辑:

 
transitionService.onBefore({}, function(transition) {
  var toState = transition.to();
  var params = transition.params();
  var requiredParams = (toState.data||{}).requiredParams || [];
  var $state = transition.router.stateService;

  var missingParams = requiredParams.filter(function(paramName) {
    return !params[paramName];
  });

  if (missingParams.length) {
    /* returning a target state from a hook 
       issues a transition redirect to that state */
    return $state.target("home", {alert: "Missing params: " + missingParams});
  }
});

然后您需要将function router($stateProvider) { $stateProvider .state('settings', { url: '/settings' }) .state('settings.show", { url: '/:id' }); } 属性添加到父声明,以使abstract路径无法访问

解决方案说明

以下是关于抽象documentation所说的内容:

  

永远无法直接激活抽象状态。使用抽象状态为子状态提供继承的属性(url,resolve,data等)。

解决方案:

/settings

注意:这只解决了function router($stateProvider) { $stateProvider .state('settings', { url: '/settings', abstract: true }) .state('settings.show", { url: '/:id' }); } 路径的问题,您仍需要使用 onBefore hook 解决方案,以便限制访问/settings