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

时间:2015-06-02 15:20:24

标签: javascript angularjs browser

我有一个控制器,应该将输入字段中的文本写入屏幕。如果我自己使用这个控制器,一切都按预期工作:

(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上是一致的。有任何想法吗?

3 个答案:

答案 0 :(得分:1)

这是因为您正在使用全局“vm”变量,该变量包含此控制器的引用。使用第二个控制器,你将参考第二个控制器覆盖vm变量。

我已更新您的代码以正确使用此引用

此外,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>

答案 1 :(得分:1)

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

但是,带有vm关键字的var位于控制器的本地范围内。结果,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>

答案 2 :(得分:0)

这是一篇关于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=preview