我正在构建一个应用程序,我希望在用户进入和离开路径时切换服务中的属性。为此,我需要了解onEnter
和onExit
挂钩中的州名称。这对于onExit
钩子来说相对容易,因为我可以注入$state
服务并读取当前状态的名称。但是,由于当调用onEnter
挂钩时尚未设置当前状态,因此无法知道我们正在转换到的状态。
我仍然需要对状态的其他部分进行精细控制,所以我宁愿没有任何for循环。我正在寻找一种能够将onEnter
函数传递给状态的方法,同时仍然在函数内部检索状态的名称。
以下是我写的代码:
function onEnter($state, Steps) {
var stateName = $state.current.name; // Not possible. The current state has not been set yet!
var step = Steps.getByStateName(stateName);
step.activate();
}
function onExit($state, Steps) {
var stateName = $state.current.name; // No problem. We know about the state.
var step = Steps.getByStateName(stateName);
step.deactivate();
}
$stateProvider
.state('step1', {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: onEnter,
onExit: onExit
});
我现在使用的解决方案是使用工厂为传递给状态的onEnter
函数创建上下文。这远非理想,因为我仍然需要将州名称传递给它。
以下是所述解决方法的示例:
function onEnterFactory(stateName) {
return function onEnter(Steps) {
var step = Steps.getByStateName(stateName);
step.activate();
}
}
$stateProvider
.state('step1', {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: onEnterFactory('step1')
});
答案 0 :(得分:4)
在我的一个项目中,我们使用了类似的东西
app.run(function($rootScope, $state, $location) {
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams,
fromState) {
$state.previous = fromState;
});
要记住以前的状态。但您可能还记得新状态并将信息存储在某处。
答案 1 :(得分:4)
在onEnter onExit挂钩上使用 此 。 onEnter由以下命令调用:
$injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
$injector.invoke
的第二个参数是它所调用的函数 this 的值。所以你的代码应如下所示:
function onEnter(Steps) {
var stateName = this.name;
var step = Steps.getByStateName(stateName);
step.activate();
}
function onExit(Steps) {
var stateName = this.name;
var step = Steps.getByStateName(stateName);
step.deactivate();
}
$stateProvider
.state('step1', {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: onEnter,
onExit: onExit
});
以下是在onEnter
和onExit
挂钩中访问州名称的工作示例:
angular.module('myApp', ['ui.router'])
.config(function($stateProvider) {
function onEnter() {
console.log('Entering state', this.name);
}
function onExit() {
console.log('Exiting state', this.name);
}
$stateProvider.state('state-1', {
url: '/state-1',
template: '<p>State 1</p>',
onEnter: onEnter,
onExit: onExit
}).state('state-2', {
url: '/state-2',
template: '<p>State 2</p>',
onEnter: onEnter,
onExit: onExit
});
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.js"></script>
<div ng-app="myApp">
<nav>
<a ui-sref="state-1">State 1</a>
<a ui-sref="state-2">State 2</a>
</nav>
<div ui-view></div>
</div>
&#13;
答案 2 :(得分:3)
您已经知道它将处于哪种状态,因为您在.state('statename',
中定义了它。要不两次写入相同的名称,可以事先定义状态变量:
var steps = ["step1", "step2", "step3"]; // or, something like Steps.getSteps()
$stateProvider
.state(steps[0], {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: function(Steps) {
var stateName = steps[0];
var step = Steps.getByStateName(stateName);
step.activate();
},
onExit: function($state, Steps) {
var stateName = $state.current.name; // No problem. We know about the state.
var step = Steps.getByStateName(stateName);
step.deactivate();
}
});
你甚至可以通过这种方式使它变得动态:
var steps = [
{ name: "step1", url: "/step1" },
{ name: "step2", url: "/step2" },
{ name: "step3", url: "/step3" }
]; // Or something like Steps.getSteps();
for (var i = 0; i < states.length; i++) {
var state = steps[i];
$stateProvider.state(state.name,
url: state.url,
templateUrl: "templates/" + state.name + ".html",
onEnter: function(Steps) {
var step = Steps.getByStateName(state.name);
step.activate();
// or just: state.activate();
},
onExit: function($state, Steps) {
var stateName = $state.current.name; // No problem. We know about the state.
var step = Steps.getByStateName(stateName);
step.deactivate();
}
}
答案 3 :(得分:1)
您可以稍微扩展您的工厂解决方案并使其更加灵活。
可能有一个provider
对状态变化作出反应。
然后你可以将这个提供者/服务注入onEnter
函数或者你可能需要的地方。
此处相关的plunker http://plnkr.co/edit/6Ri2hE
angular.module('app', ['ui.router'])
.provider('myState', function myStateProvider() {
var state;
this.onEnter = function() {
console.log('provider.onEnter', state);
};
this.$get = function($rootScope) {
var myState = {};
myState.initialize = function() {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
state = toState;
});
};
myState.getState = function() {
return state;
};
return myState;
};
})
.config(function($stateProvider, myStateProvider) {
$stateProvider
.state('step1', {
url: '/step1',
template: '<div>step1 template</div>',
controller: function() {},
onEnter: myStateProvider.onEnter // usage example
})
.state('step2', {
url: '/step2',
template: '<div>step2 template</div>',
controller: function() {},
onEnter: function(myState) { // other usage example
console.log('state.onEnter', myState.getState());
}
});
})
.run(function(myState) {
myState.initialize();
});
<a ui-sref="step1">state:step1</a>
<a ui-sref="step2">state:step2</a>
<div ui-view></div>
如果按顺序点击链接,这将console.log()
以下。
答案 4 :(得分:1)
添加一个命名状态的'name'属性:
$stateProvider
.state('step1', {
name: 'step1' // <- property naming the state
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: onEnter
});
然后this.name
回调中的onEnter
可以访问该路线的名称:
function onEnter() {
var stateName = this.name; // <- Retrieve the state's name from its configuration
var step = Steps.getByStateName(stateName);
step.activate();
}
要两次不写相同的州名,您可以先将一个状态定义在一个单独的对象中,然后在将状态添加到$stateProvider
之前用状态丰富状态:
var routes = {
"step1": {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
onEnter: onEnter
}
};
for(var routeName in routes) {
var route = routes[routeName];
// Enrich route with its name before feeding
// it to the $stateProvider
route.name = routeName;
$stateProvider.state(route.name, route);
}
答案 5 :(得分:0)
也许你可以使用resolve,
$stateProvider
.state('step1', {
url: '/step1',
templateUrl: 'templates/step1.html',
controller: 'StepOneController',
resolve: {
onenter : function( Steps ) {
// use this.self.name to access state name
var step = Steps.getByStateName(this.self.name);
step.activate();
}
}
} );
如果上面的this
方法看起来不干净,那么也许可以使用装饰器来填充当前状态。
angular.config(function($provide) {
$provide.decorator('$state', function($delegate, $rootScope) {
$rootScope.$on('$stateChangeStart', function(event, state) {
$delegate.next = state;
});
return $delegate;
});
});
状态将在$state.next
内部解析功能中可用。