Angular在$dirty
上有$pristine
和FormController
个属性,可用于检测用户是否与表单进行了互动。这两个属性或多或少都是同一枚硬币的反面。
我想实现最简单的方法来实际检测表单何时仍然处于原始状态,尽管用户与它进行交互。表格可能有任何输入。例如,如果用户首先更改某些内容,然后将其更改回初始值,我希望我的表单再次为$pristine
。
对于文本输入,这可能不是那么明显,但我有一个复选框列表,用户可以在其中切换其中一些然后改变主意...我只希望用户能够保存实际变化。问题在于,无论用户是否与列表进行交互,表单都会变脏,无论用户是否重新切换相同的复选框,使整个表单恢复到最初的状态。
一种可能的方式我可以在每个复选框中保存默认值,并为每个复选框添加ngChange
,每次都会检查所有默认值并调用$setPristine
如果所有这些都有初始值。
但我想有更好,更简单的方法来做同样的事情。也许(ab)使用验证器甚至更巧妙的东西?
在与之交互后检测表格是最原始的最简单方法是什么?
答案 0 :(得分:0)
当你的控制器初始化时:
constructor() {
super(arguments);
this._copy = angular.copy(this._formModel);
}
然后你可以把手表放在模特身上。
this._$scope.$watch('this._formModel', (new, old) => {
if (_.eq(this._copy, this._formModel)) {
formObject.$setPristine();
}
});
如果副本与模型相同,它仍然是原始的。
编辑:第二个选项是将ngChange添加到每个输入以调用控制器上的方法,然后执行与上面相同的过程。这仍然依赖于您在构造函数中复制原始(空白)模型。
<input ng-change="vm.noticeInputChange(t)" id="some_element" class="some_class" />
然后在控制器中:
noticeInputChange() {
if (_.eq(this._copy, this._formModel)) {
formObject.$setPristine();
}
}
应该这样做,但正如已经指出的那样,$ watch可能会变得非常昂贵,具体取决于表单的大小。此外,正如这里有人指出的那样,_.eq()是lodash方法
答案 1 :(得分:0)
可以通过在ngModel
内置指令中使用指令来完成,并观察模型值并在需要时对pristine进行更改。它比观看整个表格要便宜,但看起来仍然有点矫枉过正,而且我不确定大表现的表现。
注意:以下代码段不是此解决方案的最新版本,请查看 UPDATE 1 以获取最新的优化解决方案。
angular.module('app', [])
.directive('ngModel', function() {
return {
restrict: 'A',
require: ['ngModel', '^?form'],
priority: 1000, // just to make sure it will run after the built-in
link: function(scope, elem, attr, ctrls) {
var
rawValue,
ngModelCtrl = ctrls[0],
ngFormCtrl = ctrls[1],
isFormValue = function(value) {
return typeof value === 'object' && value.hasOwnProperty('$modelValue');
};
scope.$watch(attr.ngModel, function(value) {
// store the raw model value
// on initial state
if (rawValue === undefined) {
rawValue = value;
return;
}
if (value == rawValue) {
// set model pristine
ngModelCtrl.$setPristine();
// don't need to check if form is not defined
if (!ngFormCtrl) return;
// check for other named models in case are all pristine
// sets the form to pristine as well
for (key in ngFormCtrl) {
var value = ngFormCtrl[key];
if (isFormValue(value) && !value.$pristine) return;
}
// if haven't returned yet, means that all model are pristine
// so then, sets the form to pristine as well
ngFormCtrl.$setPristine();
}
});
}
};
})
.controller('myController', function($rootScope, $timeout) {
var $ctrl = this;
$ctrl.model = {
name: 'lenny',
age: 23
};
$timeout(function() {
console.log('watchers: ' + $rootScope.$$watchersCount)
}, 1000);
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['app']);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.js"></script>
<div ng-controller="myController as $ctrl">
<form name="$ctrl.myForm" novalidate>
<label>Name :
<input name="test1" ng-model="$ctrl.model.name">
</label>
<label>age :
<input name="test2" ng-model="$ctrl.model.age">
</label>
<label>Pristine: {{ $ctrl.myForm.$pristine }}</label>
<div><pre>
</pre>
</div>
</form>
</div>
&#13;
更新1
将观看系统更改为观看一次并删除额外的观察者。现在更改来自ngModelController的更改侦听器,并且观察者在第一个模型集上未绑定。正如控制台日志所注意到的那样,根目录上的观察者数量总是使观察者的数量增加一倍,通过这样做,观察者的数量保持不变。
angular.module('app', [])
.directive('ngModel', function() {
return {
restrict: 'A',
require: ['ngModel', '^?form'],
priority: 1000,
link: function(scope, elem, attr, ctrls) {
var
rawValue,
ngModelCtrl = ctrls[0],
ngFormCtrl = ctrls[1],
isFormValue = function(value) {
return typeof value === 'object' && value.hasOwnProperty('$modelValue');
};
var unbindWatcher = scope.$watch(attr.ngModel, function(value) {
// set raw value
rawValue = value;
// add a change listenner
ngModelCtrl.$viewChangeListeners.push(function() {
if (rawValue === undefined) {
//rawValue = ngModelCtrl.$lastCommit;
}
if (ngModelCtrl.$modelValue == rawValue) {
// set model pristine
ngModelCtrl.$setPristine();
// check for other named models in case are all pristine
// sets the form to pristine as well
for (key in ngFormCtrl) {
var value = ngFormCtrl[key];
if (isFormValue(value) && !value.$pristine) return;
}
ngFormCtrl.$setPristine();
}
});
// unbind the watcher at the first change
unbindWatcher();
});
}
};
})
.controller('myController', function($rootScope, $timeout) {
var $ctrl = this;
$ctrl.model = {
name: 'lenny',
age: 23
};
$timeout(function() {
console.log('watchers: ' + $rootScope.$$watchersCount)
}, 1000);
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['app']);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.js"></script>
<div ng-controller="myController as $ctrl">
<form name="$ctrl.myForm" novalidate>
<label>Name :
<input name="test1" ng-model="$ctrl.model.name">
</label>
<label>age :
<input name="test2" ng-model="$ctrl.model.age">
</label>
<label>Pristine: {{ $ctrl.myForm.$pristine }}</label>
<div><pre>
</pre>
</div>
</form>
</div>
&#13;