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
Check $pristine status of ngModel without using a form
提问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.name
in your controller or with myForm.name
in 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-change
event 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 aname
attribute, then the<form>
will be added to the$scope
object as a property.
Field controller will then be attached to theform
property.
如果你给
<form>
元素一个name
属性,那么<form>
将$scope
作为一个属性添加到对象中。
现场控制器然后将被附加到form
财产。
As weird as it could seem, you have todefine an enclosing form
with a name
attribute 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 集合为空),这也有一个附带的好处,即能够禁用提交按钮。