在不使用表单的情况下检查ngModel的$ pristine状态

时间:2014-03-03 16:09:19

标签: javascript angularjs

我试图弄清楚如何在不使用表单标签的情况下检查ngModel的状态。我没有包装器只是带有ngModel的基本输入元素。

到目前为止我找到的所有例子都是用于表格验证,在这种情况下,没有表格。

当我尝试类似的事情时:

HTML

<input type="text" ng-model="lastname">

SCRIPT:

if($scope.lastname.$dirty) {
  console.log('last name has changed');
}

我未定义。

有没有办法检查ngModel的状态而不向它添加watch指令?它似乎是基本的东西,是框架的一部分。为什么这不起作用?

3 个答案:

答案 0 :(得分:22)

有两种方法:

1。使用ng-form

<span ng-form="myForm">
  <input type="text" name="name" ng-model="name" required/>
</span>

现在,您可以在控制器中的$scope.myForm.name或视图中使用myForm.name访问模型:

var isPristine = $scope.myForm.name.$pristine;

2。使用angular.element().controller('ngModel')(不要做这个,坏坏坏)

或者,你可以破解它。但这将是丑陋的,不可测试的,粗暴的:

var elem = angular.element(document.getElementById('myElement'));
var model = elem.controller('ngModel');
var isPristine = model.$pristine;

编辑:您在转发器内的情况(根据您的评论)

  

我的例子和你的唯一区别是输入字段在ng-repeater中。认为这无关紧要,但我猜它确实如此。

现在是时候问自己你在做什么以及为什么......你仍然可以使用ng-form获得所需的信息,但你需要做一些疯狂的事情我不会不推荐:

<div ng-repeater="item in items track by $index">
  <span ng-form="rptrForm">
    <input type="text" name="name" ng-model="item.name" required/>
  </span>
</div>

..开始疯狂:

// get the first child scope (from the repeater)
var child = $scope.$$childHead;
while(child) {
  var isPristine = child.rptrForm.$pristine;
  var item = child.item;
  if(!isPristine) {
    // do something with item
  }
  child = child.$$nextSibling;
}

现在可能是重新考虑你的策略的时候了

我不确定你的最终目标是什么,但你可能想重新考虑一下你的目标和原因。为什么需要在控制器中以编程方式访问$ pristine?有什么替代品?等

我,其中一个,会尝试利用ng-change事件并在我的转发器中更新我的项目上的一些标志,并留下ng-form的内容进行验证:

<div ng-repeat="item in items track by $index" ng-form="rptrForm">
   <input type="text" name="name" ng-model="item.name" ng-change="item.nameChanged = true" required/>
   <span ng-show="rptrForm.name.$error.required>Required</span>
</div>

答案 1 :(得分:5)

  

如果您为<form>元素提供name属性,那么<form>将是   作为属性添加到$scope对象   然后,字段控制器将附加到form属性。

看起来很奇怪,你必须定义一个带有form属性的封闭式name,如下所示:

<form name="myForm">
  <input type="text" name="lastName" ng-model="lastname">
</form>

并使用以下命令调用该属性:

$scope.myForm.lastname.$dirty

确实,ngModelController(字段)附加到ngFormController(表单)。

答案 2 :(得分:0)

我使用Ben Lesh的答案来处理同样的问题。我正在显示一个通知首选项列表,我的目标是使用已更改的模型来查看我的api。不仅仅是ng-changed;价值改变了。

我首先在控制器上初始化一些私有状态:

// Private state
var originalModels = {};
var changedModels = [];

然后我存储从API检索的原始模型的副本:

// Create a hash of copies of our incoming data, keyed by the unique Code
for (var i = 0; i <= data.length - 1; i++) {
    var np = data[i];
    originalModels[np.Code] = angular.copy(np);
}

接下来,我们要确保在模型更改时,将其添加到已更改的模型集合中(如果未发生实际更改,则将其从集合中删除):

function modelChanged(m) {
    var originalModel = originalModels[m.Code];
    var hasChanged = !angular.equals(originalModel, m);

    // If the model has changed and is not present in our collection of changed models, add it
    if (hasChanged && changedModels.indexOf(m) === -1) {
        changedModels.push(m);
    }

    // If the model has not changed and is present in our collection of changed models, remove it
    if (!hasChanged && changedModels.indexOf(m) > -1) {
        var i = changedModels.indexOf(m);
        changedModels.splice(i, 1);
    }
}

最后,我们在ng-repeat中将这些联系在一起:

<tr ng-repeat="np in npc.notificationPreferences">
    <td>{{np.DisplayName}}</td>
    <td>
        <input type="checkbox"
               ng-model="np.Sms"
               ng-checked="np.Sms"
               ng-disabled="!np.SmsEnabled"
               ng-change="npc.modelChanged(np)"/>
    </td>
</tr>

现在,我只是推送已更改的模型,而不是将每一行推回到我的API。如果没有任何实际更改(即changedModels集合为空),这还有一个附带好处,即能够禁用提交按钮。