控制器之间变量名和数据的奇怪行为



我有一个控制器,应该从输入字段写入文本到屏幕。如果我单独使用这个控制器,一切都按预期工作:

(function() {
    angular.module('test', []);
    function OneCtrl() {
        vm = this;
        vm.changeHandler = changeHandler;
        vm.item = "";
        vm.value = "";
    }
    angular
        .module('test')
        .controller('OneCtrl', OneCtrl);

    var changeHandler = function() {
        vm.value = vm.item;
        console.log(vm.item);
    };

})();

试试:http://codepen.io/minuskruste/pen/qdrZqq

然而,如果我添加另一个具有相同行为的控制器,就会发生一些非常奇怪的事情。首先,字段1的输入不再发送到控制台,文本也不会插入到html正文中。其次,当我在输入字段2中输入一些东西时,它的行为是正确的。如果我现在回到字段1并在那里输入,突然字段2输入输出到控制台,即使控制器2从未被告知这样做!这是控制器2:

(function(){

function TwoController(){
    vm = this;
    vm.changeHandler = changeHandler;
    vm.item = "";
    vm.value = "";
}
angular
.module('test')
.controller('TwoController', TwoController);
var changeHandler = function() {
    vm.value = vm.item;
};

}) ();

试试:http://codepen.io/minuskruste/pen/QbpNdY

这是正常行为吗?我对此感到非常惊讶。我还检查了changeHandler()是否泄露到全局空间,但由于我把所有东西都放在闭包中,情况并非如此。此外,这在不同的平台上是一致的,例如Chrome和FF。什么好主意吗?

您遇到的部分问题是您在没有var关键字的情况下声明vm,这使其成为全局变量。

但是,var关键字的vm在控制器的本地作用域中。因此,它不再适用于changeHandler()。如果您重新排序代码并在控制器中声明changeHandler(),它将工作。

(function() {
  angular.module('test', []);
  function OneCtrl() {
    var vm = this;		
    vm.item = "";
    vm.value = "";    
    vm.changeHandler = function() {
      vm.value = vm.item;
      console.log(vm.item);
    }
  }  
  angular
  .module('test')
  .controller('OneCtrl', OneCtrl);
})();
(function(){
  function TwoController() {			
    var vm = this;		
    vm.item = "";
    vm.value = "";    
    vm.changeHandler = function() {
      vm.value = vm.item;
      console.log(vm.item);
    }
  }    
  angular
  .module('test')
  .controller('TwoController', TwoController);
})();
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>
<body ng-app="test">
  <h1>Choice array</h1>
  <div>
    <form novalidate ng-controller="OneCtrl as one">
      <input type="text" ng-change="one.changeHandler()" ng-model="one.item">
      <div>{{one.value}}</div>
    </form>
    <br><br><br>
  </div>
  <div>
    <form novalidate ng-controller="TwoController as two">
      <input type="text" ng-change="two.changeHandler()" ng-model="two.item">
      <div>{{two.value}}</div>
    </form>
  </div>
</body>

这是因为您正在使用全局"vm"变量,它包含这个控制器的引用。对于第二个控制器,您将使用第二个控制器的参考覆盖vm变量。

我已经更新了你的代码来使用正确的this引用

angular还支持另一种数据绑定方法,使用特殊的$scope对象:https://docs.angularjs.org/guide/scope

(function() {
	angular.module('test', []);
	function OneCtrl($scope) {
		// This construction makes sure I know which context is addressed. I can now hand vm (view-model) inside an object and the context doesn't change.
		this.changeHandler = angular.bind(this, changeHandler);
		this.item = "";
		this.value = "";
	}
	angular
		.module('test')
		.controller('OneCtrl', OneCtrl);
	var changeHandler = function() {
		this.value = this.item;
		console.log(this.item);
	};
})();
(function(){
	function TwoController(){
		
		// This construction makes sure I know which context is addressed. I can now hand vm (view-model) inside an object and the context doesn't change.
		this.changeHandler = angular.bind(this, changeHandler);
		this.item = "";
		this.value = "";
		
	}
	angular
	.module('test')
	.controller('TwoController', TwoController);
	var changeHandler = function() {
		this.value = this.item;
	};
})();
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>
<body ng-app="test">
	<h1>Choice array</h1>
	<div>
		<form novalidate ng-controller="OneCtrl as one">
			<input 
			type="text" 
			ng-change="one.changeHandler()" ng-model="one.item">
			<div>{{one.value}}</div>
		</form>
		<br>
		<br>
		<br>
	</div>
	<div>
		<form novalidate ng-controller="TwoController as two">
			<input 
			type="text" 
			ng-change="two.changeHandler()" ng-model="two.item">
			<div>{{two.value}}</div>
		</form>
	</div>

</body>

这是一篇关于Controller As语法的好文章。

http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/

如果你在每个控制器中声明vm变量,它将防止你看到的覆盖行为。Javascript是函数作用域的,这意味着如果它在当前函数中没有找到vm的变量声明,它将沿着原型链向上查找,直到找到声明(var vm)。如果它在全局作用域中没有找到任何声明,它将自动为您创建一个。通过在每个控制器内部声明,你可以防止它们共享相同的全局作用域。

function OneCtrl() {
    // This construction makes sure I know which context is addressed. I can now hand vm (view-model) inside an object and the context doesn't change.
    var vm = this;
    vm.item = "";
    vm.value = "";
     vm.changeHandler = function() {
      console.log(vm.item);
      vm.value = vm.item;
    };
  }

http://plnkr.co/edit/KdZvG7d2COLNcjRIfyHb?p =预览

最新更新