检测谁更改了模型(用户输入与控制器)angularjs

Detect who change the model (user input vs controller) angularjs

本文关键字:输入 控制器 angularjs 用户 模型 检测      更新时间:2023-09-26

我有一个连接到模型的输入。此外,输入具有$watch模型的指令。

模型有两种更改方式。

  1. 用户将在文本框中键入内容。
  2. 代码会改变它(不管是什么原因)

我的问题是

有没有办法找出谁在指令中更改了模型、用户交互或代码?

例:

angular.module('app', [])
.controller('ctrl', function($scope) {
})
.directive('dir', function($rootScope){
  return {
    require: 'ngModel',
    link: function(scope, element, attrs) {
      $rootScope.logs = [];
      scope.$watch(attrs.ngModel, function() {
        // here I need to check if the change was from the UI or from the controller
        
        $rootScope.logs.push('change');
      });
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ctrl">
  <input type="text" data-ng-model="model" data-dir="" />
  <button data-ng-click="model = 'asd'">Set "model" to defferent value</button>
  {{model}}
  <hr />
  <h3>console <button data-ng-click="$root.logs = []">clear console</button></h3>
  <ul>
    <li data-ng-repeat="log in $root.logs track by $index" data-ng-bind="log"></li>
  </ul>
</div>

http://jsbin.com/vufawur/edit?html,js,output

更新

示例 2:

angular.module('app', [])
.controller('ctrl', function($scope, $timeout) {
  $timeout(function() {
      $scope.model = 'asd';
  }, 3000);
})
.directive('dir', function($rootScope){
  return {
    require: 'ngModel',
    link: function(scope, element, attrs) {
      $rootScope.logs = [];
      scope.$watch(attrs.ngModel, function() {
        // here I need to check if the change was from the UI or from the controller
        $rootScope.logs.push('change');
      });
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ctrl">
  ...wait until data "return from the server"<br />
  <input type="text" data-ng-model="model" data-dir="" />
  
  {{model}}
  <hr />
  <h3>console <button data-ng-click="$root.logs = []">clear console</button></h3>
  <ul>
    <li data-ng-repeat="log in $root.logs track by $index" data-ng-bind="log"></li>
  </ul>
</div>

ext-change ng-model的外部变更指令

使用$viewChangeListener保存最后一个用户输入,并让监视处理程序进行比较,以区分对模型的外部更改和对模型的用户输入更改。

.directive('extChange', function(){
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, modelCtrl) {
        var lastUserInput = modelCtrl.$viewValue;
        modelCtrl.$viewChangeListeners.push(function() {
            lastUserInput = modelCtrl.$viewValue;
        });
        scope.$watch(attrs.ngModel, function watchHandler (value) {
            if (value!==lastUserInput) {
                scope.$eval(attrs.extChange, {$value:value});
            }                
        });
    }
  }
});

示例指令保存最后一个用户输入。当监视处理程序获取不同的值时,它将调用由 ext-change 属性定义的 Angular 表达式。更改的值显示为 $value

<input ng-model="someInput"
       ng-change="userInput=someInput"
       ext-change="extInput=$value">

ext-change指令与ng-model指令配合使用,是对ng-change指令的补充。

在此示例中,ext-change 指令仅在对模型进行外部更改时更新 extInput 变量。ng-change 指令仅更新用户更改的 userInput 变量。

JSFiddle 上的演示


该指令还可用于调用函数。

<input ng-model="someInput"
       ng-change="userEvent(someInput)"
       ext-change="externalEvent($value)">

不要使用 $watch 。你不应该使用它,你必须不使用它,如果你使用$watch你就会遇到麻烦,你已经有麻烦了,不要使用它。

  • Angular JS - 你可能不应该在你的控制器中使用$watch。
  • 在控制器中使用角度$watch是一种反模式吗?

使用控制流和事件。有可能你已经有很多观察者和范围汤,现在还不算太晚,尽快重构,这是为了你最好的。

angular.module('app', [])
  .controller('ctrl', function($scope) {
  })
  .directive('dir', function($rootScope) {
    return {
      require: 'ngModel',
      link: function($scope, element, attrs) {
        $rootScope.logs = [];
        $scope.modelChange = function(reason) {
          $rootScope.logs.push(reason);
        };
        $scope.modelChangedFromInput = function(model) {
          $scope.modelChange('From input');
        };
        $scope.buttonClick = function() {
          $scope.model = 'asd';
          $scope.modelChange('From button');
        };
      }
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ctrl">
  <input type="text" data-ng-model="model" data-dir="" data-ng-change="modelChangedFromInput()" />
  <button data-ng-click="buttonClick()">Set "model" to different value</button>
  {{model}}
  <hr />
  <h3>console <button data-ng-click="$root.logs = []">clear console</button>
  </h3>
  <ul>
    <li data-ng-repeat="log in $root.logs track by $index" data-ng-bind="log"></li>
  </ul>
</div>