即使我看到变量在事件监听器中更新,但是当状态更改事件发生时,我没有更新到$scope
函数的变量有问题。
以下是代码:
angular.module('testapp')
.controller('AnotherCtrl',
['$scope', '$rootScope', '$state',
function ($scope, $rootScope, $state) {
'use strict';
console.log("Init prevState.");
var prevState = 'null_state';
$scope.state = prevState;
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
console.log("Error");
if (toState.name === 'anotherState') {
console.log("Old State:" + prevState);
prevState = fromState.name;
console.log("New State:" + prevState);
}
})
$rootScope.$on('$stateChangeSuccess',
function (event, toState, toParams, fromState, fromParams) {
console.log("Success");
if (toState.name === 'anotherState') {
console.log("Old State:" + prevState);
prevState = fromState.name;
console.log("New State:" + prevState);
}
})
$scope.goBack = function () {
//$scope.state = 'anotherState';
console.log("goBack:" + prevState);
$state.transitionTo(prevState, {arg: 'Robert'});
};
}]);
以下是HTML模板:
<div>
<h1>Another view</h1>
<br>
<br>
State: <span ng-model="state">{{state}}</span>
<br>
<br>
<button ng-click="goBack()">Back</button>
</div>
这是控制台输出:
因此,当我按下调用函数goBack()
的按钮上的按钮时,prevState
变量仍为'null_state'
。
任何人都可以解释问题是什么吗?
在审核答案后更新 我已经审核并测试了所有建议的解决方案。核心问题AFAICS与字符串类型是不可变的无关。我认为最好的答案来自@Khanh TO。首先创建控制器时,事件侦听器未初始化。这是用bootstrapping(angular.module.run)修复的。每次加载状态/视图时,控制器都会重新初始化,导致变量prevState被重新初始化,因此监听器函数和goBack()函数使用不同的外部prevState变量。在rootScope上存储prevState解决了这个问题。
答案 0 :(得分:1)
根本原因是无论何时更改状态,角度重新初始化与当前状态关联的控制器,导致先前存储的状态为已清除且为-initialized 强>
因此,解决方案是将先前状态存储在共享服务中。在这种情况下,我们可以使用$rootScope
。
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
console.log("Error");
if (toState.name === 'anotherState') {
$rootScope.prevState = fromState.name;
}
});
$rootScope.$on('$stateChangeSuccess',
function (event, toState, toParams, fromState, fromParams) {
console.log("Success");
if (toState.name === 'anotherState') {
$rootScope.prevState = fromState.name;
}
});
$scope.goBack = function () {
$state.transitionTo($rootScope.prevState, {arg: 'Robert'});
//or $state.transitionTo($scope.prevState, {arg: 'Robert'}); //due to scope inheritance
};
但是,只要$rootScope
重新初始化,您的代码就会向AnotherCtrl
注册越来越多的事件处理程序。您的代码的第二个问题是第一次加载页面时$stateChangeSuccess
事件不会触发https://github.com/angular-ui/ui-router/issues/299
您应该只在.run
块中注册一次事件处理程序:
angular.module('testapp')
.run(["$rootScope",function ($rootScope){
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
console.log("Error");
if (toState.name === 'anotherState') {
$rootScope.prevState = fromState.name;
}
});
$rootScope.$on('$stateChangeSuccess',
function (event, toState, toParams, fromState, fromParams) {
console.log("Success");
if (toState.name === 'anotherState') {
$rootScope.prevState = fromState.name;
}
});
}]);
只有这些代码应保留在您的控制器中:
$scope.goBack = function () {
$state.transitionTo($rootScope.prevState, {arg: 'Robert'});
//or $state.transitionTo($scope.prevState, {arg: 'Robert'}); //due to scope inheritance
};
答案 1 :(得分:0)
您面临的问题是JavaScript闭包的工作原理。当您在函数goBack()的范围内访问prevState以及与stateChangeSuccess相关联的函数时,您将保留父亲的prevState句柄。但JavaScript中的字符串是不可变的。因此,当在goBack中为prevState分配值时,会创建一个新字符串,并且goBack()内的prevState指向该字符串。但是与stateChangeSuccess相关联的prevState仍然指向&#34; null_state&#34;。
您可以做的是将prevState包装在对象中:
var prevData = {prevState: 'null_state'};
并使用prevData.prevState
修改prevState。这将起作用的原因是因为所有闭包都保存对同一对象的引用(因为现在您使用的是对象而不是字符串),因此对字符串的更改将传播到不同的函数。
有关详细信息,请仔细阅读以下内容:
答案 2 :(得分:0)
每次更改路线时,当前控制器被销毁(广播$ destroy事件)并创建新控制器。
您可以看到控制器在控制器内被销毁的时间:
$scope.$on('$destroy',function () {
console.log("The controller is destroyed.");
});
在应用程序中维护数据的方法是通过服务(如$ state)或 $ rootScope 。
这意味着在创建控制器时,您可以从服务获取数据。为此创建一个getter函数。
另一方面,如果要将数据与控制器绑定,则必须更新$ scope.state,而不是prevState。模板仅更新$ scope的值。
结果:
angular.module('testapp')
.controller('AnotherCtrl',
['$scope', '$rootScope', '$state',
function ($scope, $rootScope, $state) {
'use strict';
console.log("Init prevState.");
$scope.state = $state.getState(); //create the getter
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
console.log("Error");
if (toState.name === 'anotherState') {
console.log("Old State:" + $scope.state);
$scope.state = fromState.name;
console.log("New State:" + $scope.state);
}
})
$rootScope.$on('$stateChangeSuccess',
function (event, toState, toParams, fromState, fromParams) {
console.log("Success");
if (toState.name === 'anotherState') {
console.log("Old State:" + $scope.state);
$scope.state = fromState.name;
console.log("New State:" + $scope.state);
}
})
$scope.goBack = function () {
//$scope.state = 'anotherState';
console.log("goBack:" + $scope.state);
$state.transitionTo($scope.state, {arg: 'Robert'});
};
}]);
答案 3 :(得分:0)
可能你想改变:
var prevState = 'null_state';
到
$scope.prevState = 'null_state';
并相应地修复其他内容。