Javascript 变量更改在my$scope函数中不可见
当发生状态更改事件时,即使在事件侦听器中看到变量已更新,但变量未更新为Javascript 变量更改在my$scope函数中不可见,javascript,angularjs,Javascript,Angularjs,当发生状态更改事件时,即使在事件侦听器中看到变量已更新,但变量未更新为$scope函数,我对此有问题 代码如下: angular.module('testapp') .controller('AnotherCtrl', ['$scope', '$rootScope', '$state', function ($scope, $rootScope, $state) { 'use strict'; console.log("Init prevState.");
$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>
另一种观点
状态:{{State}}
返回
以下是控制台输出:
因此,当我按下按钮上调用函数goBack()
的按钮时,prevState
变量仍然是'null\u state'
有人能解释问题出在哪里吗
查看答案后更新
我已经审查并测试了所有建议的解决方案。核心问题AFAICS与字符串类型不可变无关。在我看来,最好的答案来自@Khanh TO。首先创建控制器时,事件侦听器未初始化。这是通过引导(angular.module.run)修复的。此外,每次加载状态/视图时都会重新初始化控制器,从而导致变量prevState重新初始化,因此侦听器函数和goBack()函数使用不同的外部prevState变量。将prevState存储在rootScope上解决了此问题。根本原因是每当更改状态时,angular都会重新初始化与当前状态关联的控制器,从而清除先前存储的状态并重新初始化 因此,解决方案是将以前的状态存储在共享服务中。在这种情况下,我们可以只使用
$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
};
但是,每当另一个Ctrl
被重新初始化时,您的代码就会遇到一个严重的问题:将越来越多的事件处理程序注册到$rootScope
。代码的第二个问题是首次加载页面时不会触发$stateChangeSuccess
事件
您应该只在中注册一次事件处理程序。运行块:
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
};
$scope.$on('$destroy',function () {
console.log("The controller is destroyed.");
});
您面临的问题是JavaScript闭包的工作方式。当您在函数goBack()和与stateChangeSuccess关联的函数的作用域中访问prevState时,您将保留父级prevState的句柄。但是JavaScript中的字符串是不可变的。因此,在goBack中为prevState赋值时,将创建一个新字符串,goBack()中的prevState将指向该字符串。但是与stateChangeSuccess关联的prevState仍然指向“null_状态”
您可以将prevState包装到对象中,如下所示:
var prevData = {prevState: 'null_state'};
并使用prevData.prevState
修改prevState。这将起作用的原因是,所有闭包都持有对同一对象的引用(因为现在使用的是对象而不是字符串),因此对字符串的更改将传播到不同的函数
有关更多信息,请仔细阅读以下内容:
每次更改路由时,当前控制器将被销毁(广播$destroy事件),并创建一个新控制器
当控制器被破坏时,您可以在控制器内看到:
$scope.goBack = function () {
$state.transitionTo($rootScope.prevState, {arg: 'Robert'});
//or $state.transitionTo($scope.prevState, {arg: 'Robert'}); //due to scope inheritance
};
$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'});
};
}]);
您可能想要更改:
var prevState = 'null_state';
到
并相应地修复其他内容。您也可以共享与此控制器相关的HTML吗?我也这么认为,但如果控制器重新初始化,为什么“Init prevState”控制台打印不会显示在他的控制台屏幕截图上?这是控制器做的第一件事。@haimlit:控制台中有“Init prevState.”
。请仔细看看。但是如果你说的是正确的,那么应该有两种情况——一种是控制器初始化时,另一种是由于状态更改而重新初始化时。@haimlit:看看代码,我们可以看出他来自“modeltest.transfer”
,应该只有一个“Init prevState”
。我使用的是angular 1.2.17,流程如下:$stateChangeSuccess
在重新初始化控制器之前首先触发(在控制台中记录“Init prevState.”
)。我还觉得控制台有问题,因为“Init prevState”。
应该介于“New State”
和“go back”
之间。不确定在其他版本中,控制器初始化是在$stateChangeSuccess
@haimlit之前运行的:我不确定他是如何重现这种情况的。这可能与我上面提到的问题有关。代码第一次不起作用,每当我们达到这种状态时,事件处理程序就会被注册得越来越多。