ng-change 检测 ng 模型在选择框中为空或无效,然后选择第一个有效选项

ng-change detect if ng-model is null or invalid in select box and select first valid option

本文关键字:选择 无效 然后 选项 有效 第一个 ng 检测 模型 ng-change      更新时间:2023-09-26

我有数百个这样的案例(所以修复必须是全局的,而不仅仅是这个特定的例子)

有很多这样的选择框:

<select ng-model="selectedItem">
 <option ng-repeat="item in items | filter:attributes" value="{{item.id}}">{{item.name}}</option>
</select>

selectedItem变量为 null(它将始终初始化为 null,在此特定情况下无法在控制器中更改)。

我想弄清楚的是一种全局监视视图中所有<select>元素的方法,查看该<select>框的ng-model变量是否null,如果null将其设置为该选择框中的第一个有效选项,每当范围更改时,它都需要检查 ng-model 是否null并自动选择第一个有效选项。

要意识到这一点的关键是,您可以定义多个具有相同名称的 Angular 指令,并且所有这些指令都将为匹配的元素运行。

这非常强大,因为它使您能够扩展内置指令或第三方指令等的功能。

使用它,我能够创建一个 select 指令,只要模型值为 null,它就会选择列表中的第一个有效选项。

但是,它不做的一件事是,如果您从列表中删除所选项目(它又恢复为空白),则可应对。但希望这足以让你开始。

var app = angular.module('stackoverflow', []);
app.controller('MainCtrl', function($scope) {
  $scope.selectedItem = null;
  $scope.items = [1, 2, 3, 4].map(function(id) {
    return {
      id: id,
      visible: true,
      text: 'Item ' + id
    };
  });
});
app.directive('select', function() {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function($scope, $elem, $attrs, ngModel) {
      // don't do anything for selects without ng-model attribute
      if (!ngModel) return;
      // also allow specifying a special "no-default" attribute to opt out of this behaviour
      if ($attrs.hasOwnProperty('noDefault')) return;
      // watch the model value for null
      var deregWatch = $scope.$watch(function() {
        return ngModel.$modelValue;
      }, function(modelValue) {
        if (modelValue === null) {
          // delay to allow the expressions to be interpolated correctly
          setTimeout(function() {
            // find the first option with valid text
            var $options = $elem.find('option'),
              $firstValidOption, optionText;
            for (var i = 0, len = $options.length; i < len; i++) {
              optionText = $options.eq(i).text();
              if (optionText !== '' && !optionText.match(/^('?|{)/)) {
                $firstValidOption = $options.eq(i);
                break;
              }
            }
            if ($firstValidOption) {
              $firstValidOption.prop('selected', true);
              ngModel.$setViewValue($firstValidOption.attr('value'));
              // trigger a digest so Angular sees the change
              $scope.$evalAsync();
            }
          }, 0);
        }
      });
      // clean up in destroy method to prevent any memory leaks
      var deregDestroy = $scope.$on('$destroy', function() {
        deregWatch();
        deregDestroy();
      });
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="stackoverflow">
  <div ng-controller="MainCtrl">
    <select ng-model="selectedItem">
      <option ng-repeat="item in items | filter:{visible:true} track by item.id" value="{{item.id}}">{{item.text}}</option>
    </select>
    <p>Visible items:</p>
    <ul>
      <li ng-repeat="item in items track by item.id">
        <label>
          <input type="checkbox" ng-model="item.visible">{{item.text}}
        </label>
      </li>
    </ul>
  </div>
</div>