1.3.0 rc0 </select>之后<select>的ngChange问​​题

时间:2014-11-04 09:42:41

标签: angularjs

我一直在使用1.3的测试版,现在转移到1.3.1后我发现一个问题,通过检查所有早期版本,我看到它似乎已经开始在 1.3.0 rc1

我有这样的代码:

<select ng-model="home.modal.topicId"
        ng-change="ctrl.modalTopicChanged()"
        ng-options="item.id as item.name for item in home.modal.option.topics.data"
        ng-required="true">
        <option style="display: none;" value="">Select Topic</option>
</select>

在表格首次显示之前,在rc1之前,ng-change 未被解雇。现在它被一个未定义的home.modal.topicId解雇了。这对我来说是一个突破性的变化,但在破坏性变化部分没有提到它,我想知道它是否是一个尚未被注意到的错误。

这是产生的堆栈跟踪:

TypeError: Cannot read property 'dataMap' of undefined
    at AdminProblemController.modalTopicChanged (http://127.0.0.1:17315/Content/app/admin/controllers/ProblemController.js:109:114)
    at $parseFunctionCall (http://127.0.0.1:17315/Scripts/angular.js:11387:18)
    at Scope.$get.Scope.$eval (http://127.0.0.1:17315/Scripts/angular.js:13276:28)
    at http://127.0.0.1:17315/Scripts/angular.js:19888:13
    at http://127.0.0.1:17315/Scripts/angular.js:19499:9
    at forEach (http://127.0.0.1:17315/Scripts/angular.js:331:20)
    at $$writeModelToScope (http://127.0.0.1:17315/Scripts/angular.js:19497:5)
    at writeToModelIfNeeded (http://127.0.0.1:17315/Scripts/angular.js:19490:14)
    at http://127.0.0.1:17315/Scripts/angular.js:19484:9
    at validationDone (http://127.0.0.1:17315/Scripts/angular.js:19420:9) 

我在这里注意到一个新功能:writeToModelIfNeeded

当我查看更改日志差异时,在检查所有更改和行号时,我找不到提及此功能的任何内容。

我想就此提出一些建议。首先是可以找到导致添加writeToModelIfNeeded的更改,其次是选择框的正确功能。我认为整个想法是只有在定义模型值时才会触发ng-change。

这里的参考是新代码的区域,似乎已经添加了1.3.0 rc.1

**
   * @ngdoc method
   * @name ngModel.NgModelController#$commitViewValue
   *
   * @description
   * Commit a pending update to the `$modelValue`.
   *
   * Updates may be pending by a debounced event or because the input is waiting for a some future
   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
   * usually handles calling this in response to input events.
   */
  this.$commitViewValue = function() {
    var viewValue = ctrl.$viewValue;

    $timeout.cancel(pendingDebounce);

    // If the view value has not changed then we should just exit, except in the case where there is
    // a native validator on the element. In this case the validation state may have changed even though
    // the viewValue has stayed empty.
    if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
      return;
    }
    ctrl.$$lastCommittedViewValue = viewValue;

    // change to dirty
    if (ctrl.$pristine) {
      ctrl.$dirty = true;
      ctrl.$pristine = false;
      $animate.removeClass($element, PRISTINE_CLASS);
      $animate.addClass($element, DIRTY_CLASS);
      parentForm.$setDirty();
    }
    this.$$parseAndValidate();
  };

  this.$$parseAndValidate = function() {
    var parserValid = true,
        viewValue = ctrl.$$lastCommittedViewValue,
        modelValue = viewValue;
    for(var i = 0; i < ctrl.$parsers.length; i++) {
      modelValue = ctrl.$parsers[i](modelValue);
      if (isUndefined(modelValue)) {
        parserValid = false;
        break;
      }
    }
    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
      // ctrl.$modelValue has not been touched yet...
      ctrl.$modelValue = ngModelGet();
    }
    var prevModelValue = ctrl.$modelValue;
    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
    if (allowInvalid) {
      ctrl.$modelValue = modelValue;
      writeToModelIfNeeded();
    }
    ctrl.$$runValidators(parserValid, modelValue, viewValue, function() {
      if (!allowInvalid) {
        ctrl.$modelValue = ctrl.$valid ? modelValue : undefined;
        writeToModelIfNeeded();
      }
    });

    function writeToModelIfNeeded() {
      if (ctrl.$modelValue !== prevModelValue) {
        ctrl.$$writeModelToScope();
      }
    }
  };

  this.$$writeModelToScope = function() {
    ngModelSet(ctrl.$modelValue);
    forEach(ctrl.$viewChangeListeners, function(listener) {
      try {
        listener();
      } catch(e) {
        $exceptionHandler(e);
      }
    });
  };

1 个答案:

答案 0 :(得分:5)

我能够通过这样做来重现您的问题。没有看到你的控制器,但不确定是否相同:

 this.modal = {
      topicId:null,
      option:{
        topics:{
          data:[{id:1,name:'item1'},{id:2,name:'item2'}]
        }
      }
    };

这里发生的是angular表示null是一个无效值,因此默认情况下将其设置为undefined。您可以通过将其设置为“未定义”或将其添加到您的html来解决此问题:

ng-model-options="{allowInvalid:true}"

还测试了Josep plunker并将该值更改为null也导致ngChange触发