简体   繁体   English

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

[英]Strange behavior with variable names and data between controllers

I have a controller that is supposed to write text from an input field to the screen. 我有一个控制器,应该将输入字段中的文本写到屏幕上。 If I use this controller by itself everything works as expected: 如果我自己使用此控制器,那么一切都会按预期进行:

(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);
    };


})();

Try here: http://codepen.io/minuskruste/pen/qdrZqq 在这里尝试: http : //codepen.io/minuskruste/pen/qdrZqq

However, if I add another controller with the same behavior something really weird happens. 但是,如果我添加另一个具有相同行为的控制器,则会发生一些奇怪的事情。 First of all, the input from field 1 is not sent to console anymore and the text is also not inserted into the html body. 首先,来自字段1的输入不再发送到控制台,并且文本也不会插入html主体中。 Second of all, when I type something into input field 2 it behaves correctly. 第二,当我在输入字段2中键入内容时,它的行为正确。 If I now go back to field 1 and type there, suddenly field 2 input is output to console, even though controller two was never told to do so! 如果我现在回到字段1并在其中键入内容,则即使从未告知控制器2这样做,字段2的输入也会突然输出到控制台! This is controller 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;
};

})(); })();

Try here: http://codepen.io/minuskruste/pen/QbpNdY 在这里尝试: http : //codepen.io/minuskruste/pen/QbpNdY

Is this normal behavior? 这是正常行为吗? I was very surprised by it. 我对此感到非常惊讶。 I also checked if maybe the changeHandler() leaked to global space but since I've put everything in closures that's not the case. 我还检查了是否changeHandler()泄漏到全局空间,但是由于我将所有内容都放入了闭包中,所以情况并非如此。 Furthermore this is consistent over different platforms ie Chrome and FF. 此外,这在不同的平台(例如Chrome和FF)上是一致的。 Any ideas? 有任何想法吗?

This happens because you're using global "vm" variable, which containg this reference of controller. 发生这种情况是因为您使用的是全局“ vm”变量,其中包含控制器的此引用。 And with second controller you're overwriting vm variable with reference to second controller. 使用第二个控制器,您将参照第二个控制器覆盖vm变量。

I've updated your code to use proper this references 我已经更新了您的代码以使用正确的引用

Also angular supports another data binding approach with special $scope object: https://docs.angularjs.org/guide/scope 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> 

Part of the issue you are having is that you are declaring vm without the var keyword, which makes it a global variable. 您遇到的部分问题是,您声明的vm没有var关键字,这使其成为全局变量。

However, vm with the var keyword is in the local scope of the controller. 但是,带有var关键字的vm在控制器的本地范围内。 As a result, it's not available to the changeHandler() anymore. 结果,它不再对changeHandler()可用。 If you reorder your code and declare changeHandler() inside the controller, it will work. 如果您对代码重新排序并在控制器内部声明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> 

Here is a good article on the Controller As syntax. 这是一篇关于Controller As语法的好文章。

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

If you declare the vm variable in each controller it will prevent the overwriting behavior you are seeing. 如果在每个控制器中声明vm变量,它将防止您看到的覆盖行为。 Javascript is functional scoped, which means if it doesn't find the variable declaration for vm in the current function, it will go up the prototypical chain until it finds the declaration (var vm). Javascript具有功能范围,这意味着如果它在当前函数中找不到vm的变量声明,它将沿着原型链向上移动,直到找到声明(var vm)。 If it doesn't find any declaration in the global scope, it will automatically create one for you. 如果在全局范围内找不到任何声明,它将自动为您创建一个声明。 By declaring inside each controller you will prevent them from both sharing the same global scope. 通过在每个控制器内部声明,可以防止它们共享相同的全局范围。

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 http://plnkr.co/edit/KdZvG7d2COLNcjRIfyHb?p=preview

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM