我需要一种方法来遍历AngularJS表单的已注册控件。本质上,我正在尝试获取所有$ dirty控件,但是没有控件数组(FormController除了包含控件本身之外还有许多不同的属性/函数 - 每个都是它自己的对象)。
我一直在查看源代码,我发现FormController中有一个controls
数组,它正是我正在寻找的数组。有没有办法访问此值,或扩展FormController以包含一个返回此controls
数组的函数?
修改:Plnkr演示
另外,我意识到技术上我可以检查键字符串中的第一个字符“$”,但我想避免在未来版本的Angular中FormController /指令发生变化。
编辑2:另一个澄清:我所有这一切的目标是能够确定哪些特定字段是$ dirty,是否通过循环遍历整个控件列表(不包括$ dirty,$ invalid,$ error, $ name,以及生活在Form对象中的其他属性)或者通过扩展FormController并创建一个只返回当前脏的控件(并且不等于它们的起始值)的函数
编辑3:我正在寻找的解决方案需要适用于不同结构的表单/模型。范围上的模型是通过AJAX生成的,因此它们的结构已经设置好了(我想避免为我已经通过AJAX接收的所有数据硬编码新结构)。此外,我希望在多个表单/模型中使用此表单提交过程,并且每个表单都具有不同的JSON结构 - 因为它们适用于对象模型中的不同实体。这就是为什么我选择了一种方法来访问FormController中的controls
对象(我将从下面的FormController
发布代码),因为这是我唯一能够访问的地方得到我所有领域的平面数组。
function FormController(element, attrs) {
var form = this,
parentForm = element.parent().controller('form') || nullFormCtrl,
invalidCount = 0, // used to easily determine if we are valid
errors = form.$error = {},
controls = [];
// init state
form.$name = attrs.name || attrs.ngForm;
form.$dirty = false;
form.$pristine = true;
form.$valid = true;
form.$invalid = false;
parentForm.$addControl(form);
// Setup initial state of the control
element.addClass(PRISTINE_CLASS);
toggleValidCss(true);
// convenience method for easy toggling of classes
function toggleValidCss(isValid, validationErrorKey) {
validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
element.
removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
}
/**
* @ngdoc function
* @name ng.directive:form.FormController#$addControl
* @methodOf ng.directive:form.FormController
*
* @description
* Register a control with the form.
*
* Input elements using ngModelController do this automatically when they are linked.
*/
form.$addControl = function(control) {
controls.push(control);
if (control.$name && !form.hasOwnProperty(control.$name)) {
form[control.$name] = control;
}
};
/**
* @ngdoc function
* @name ng.directive:form.FormController#$removeControl
* @methodOf ng.directive:form.FormController
*
* @description
* Deregister a control from the form.
*
* Input elements using ngModelController do this automatically when they are destroyed.
*/
form.$removeControl = function(control) {
if (control.$name && form[control.$name] === control) {
delete form[control.$name];
}
forEach(errors, function(queue, validationToken) {
form.$setValidity(validationToken, true, control);
});
arrayRemove(controls, control);
};
// Removed extra code
}
如您所见,表单本身具有私有的controls
数组。我想知道是否有办法扩展FormController
以便我可以公开该对象?或者创建一个公共函数,这样我至少可以查看私有数组?
答案 0 :(得分:19)
要直接解决问题,请修改@ lombardo的答案;
var dirtyFormControls = [];
var myForm = $scope.myForm;
angular.forEach(myForm, function(value, key) {
if (typeof value === 'object' && value.hasOwnProperty('$modelValue') && value.$dirty)
dirtyFormControls.push(value)
});
数组'dirtyFormControls'将包含脏的表单控件。
您还可以使用此技巧在表单提交时显示“必需”验证和所有其他验证的错误消息。在submit()函数中,您将执行类似的操作;
if (form.$invalid) {
form.$setDirty();
angular.forEach(form, function(value, key) {
if (typeof value === 'object' && value.hasOwnProperty('$modelValue'))
value.$setDirty();
});
//show user error summary at top of form.
$('html, body').animate({
scrollTop: $("#myForm").offset().top
}, 1000);
return;
}
在您的表单中,您将显示错误消息
<span ng-messages="myForm['subject-' + $index].$error" ng-show="myForm['subject-' + $index].$dirty" class="has-error">
<span ng-message="required">Course subject is required.</span>
</span>
当您使用'ng-repeat'或类似的东西动态生成控件时,上述解决方案非常有用。
答案 1 :(得分:11)
您可以使用以下代码迭代控件:
var data = {};
angular.forEach(myForm, function (value, key) {
if (value.hasOwnProperty('$modelValue'))
data[key] = value.$modelValue;
});
答案 2 :(得分:2)
在您的控制器内轻松尝试:
$scope.checkForm = function(myFormName){
console.log(myFormName.$invalid);
}
更新:
<div ng-controller="MyController">
<form name="form" class="css-form" novalidate>
<input type="text" ng-model="user.uname" name="uname" required /><br />
<input type="text" ng-model="user.usurname" name="usurname" required /><br />
<button ng-click="update(form)">SAVE</button>
</form>
</div>
app.controller('MyController',function($scope){
$scope.user = {};
$scope.update = function (form){
var editedFields = [];
angular.forEach($scope.user, function(value, key){
if(form[key].$dirty){
this.push(key + ': ' + value);
}
}, editedFields);
console.log(editedFields);
}
});
答案 3 :(得分:0)
我提出了一个不错的解决方案,但仍然不是我想要的。我从另一个涉及从字符串创建JSON对象的问题中挽救了一些代码,并提出以下内容:
基本上我是以与模型绑定相同的方式命名我的字段,然后在调用form_submit时构建一个新对象以供提交。
在演示中,如果你更改了任何一个表单字段,然后点击提交,你会看到弹出的对象只有脏值。