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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22151577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 22:33:41  来源:igfitidea点击:

Check $pristine status of ngModel without using a form

javascriptangularjs

提问by J Castillo

Am trying to figure out how to check the state of a ngModel without using a form tag. I don't have wrappers is just basic input element with a ngModel.

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

All the examples I have found so far are for form validations and in this case, there is no form.

到目前为止,我发现的所有示例都用于表单验证,在这种情况下,没有表单。

When i tried something like:

当我尝试类似的事情时:

HTML

HTML

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

SCRIPT:

脚本:

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

I get undefined.

我得到未定义。

Is there a way to check the state of the ngModel without adding a watch directive to it? it seems it would be something basic that is part of the framework. Why wouldn't this work?

有没有办法在不添加 watch 指令的情况下检查 ngModel 的状态?似乎它是框架的一部分。为什么这行不通?

回答by Ben Lesh

There are two ways:

有两种方式:

1. Use ng-form:

1. 使用ng-form

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

Now you can access the model either at $scope.myForm.namein your controller or with myForm.namein your view:

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

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

2. Use angular.element().controller('ngModel')(Don't do this one, bad bad bad)

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

Alternatively, you could hack your way around it. But this is going to be ugly, untestable, and gross:

或者,您可以绕过它。但这将是丑陋的、不可测试的和粗暴的:

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


Edit: Your situation (per your comment) inside of a repeater

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

the only difference between my example and your is that the input field is inside a ng-repeater. Thought that wouldn't matter but I guess it does.

我的示例和您的示例之间的唯一区别是输入字段位于 ng-repeater 内。认为这无关紧要,但我想它确实如此。

And now it's time to ask yourself what you're doing and why... You can still get the information you need using ng-form, but you'll need to do some crazy stuff I wouldn't recommend:

现在是时候问问自己你在做什么以及为什么......你仍然可以使用 获得你需要的信息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>

.. commence craziness:

.. 开始疯狂:

// 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;
}

It's probably time to rethink your strategy

可能是时候重新考虑您的策略了

I'm not sure what your end goal is, but you might want to rethink how you're going about it and why. Why do you need programmatic access to $pristine in your controller? What alternatives are there? Etc.

我不确定你的最终目标是什么,但你可能想重新考虑你是如何去做的以及为什么。为什么需要对控制器中的 $pristine 进行编程访问?有哪些替代方案?等等。

I, for one, would try to leverage an ng-changeevent and update some flag on my item in my repeater, and leave the ng-form stuff for validation:

一方面,我会尝试利用一个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>

回答by Mik378

If you give the <form>element a nameattribute, then the <form>will be added to the $scopeobject as a property.
Field controller will then be attached to the formproperty.

如果你给<form>元素一个name属性,那么<form>$scope作为一个属性添加到对象中。
现场控制器然后将被附加到form财产。

As weird as it could seem, you have todefine an enclosing formwith a nameattribute like so:

尽管看起来很奇怪,但您必须定义一个form带有如下name属性的封闭:

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

and call the property with:

并通过以下方式致电该物业:

$scope.myForm.lastname.$dirty

Indeed, ngModelController(field) is attached to ngFormController(form).

事实上,ngModelController(字段)附加到ngFormController(形式)。

回答by Adam Skinner

I used Ben Lesh's answer to deal with the same problem. I was displaying a list of notification preferences, and my goal was to hit my api with models that had changed. Not just ng-changed, either; value changed.

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

I start by initializing some private state on my controller:

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

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

Then I store copies of the original models retrieved from the API:

然后我存储从 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);
}

Next, we want to make sure that when a model changes, we add it to a changed models collection (or remove it from the collection if no real change occurred):

接下来,我们要确保当模型更改时,我们将其添加到已更改的模型集合中(如果没有发生真正的更改,则将其从集合中删除):

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

Finally, we tie these together in our ng-repeat:

最后,我们在 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>

Now, instead of pushing back every row to my API, I simply push the changed models. This also has a side benefit of being able to ng-disable your submit button if nothing has actually changed (ie the changedModels collection is empty).

现在,我不再将每一行都推回到我的 API 中,而是简单地将更改后的模型推送出去。如果实际上没有任何更改(即 changedModels 集合为空),这也有一个附带的好处,即能够禁用提交按钮。