我需要一种方法来遍历AngularJS表单的注册控件。本质上,我试图获取所有的$ dirty控件,但是没有控件数组(FormController除了包含控件本身以外,还具有许多不同的属性/函数-每个控件都是自己的对象)。
我一直在查看源代码,并且看到controlsFormController中有一个数组正是我要查找的数组。有没有一种方法可以访问此值,或者扩展FormController使其包含返回此controls数组的函数?
controls
编辑:Plnkr演示
另外,我意识到从技术上讲,我可以检查键字符串中的第一个字符“ $”,但是我想避免这种情况,以防FormController /指令在Angular的未来版本中发生更改。
编辑2:另一个说明:我所有的目标是能够通过遍历整个控件列表(不包括$ dirty,$ invalid,$ error,$ name,以及其他保留在Form对象中的属性),或者通过扩展FormController并创建一个仅返回当前脏控件(且不等于其初始值)的函数来创建
编辑3:我正在寻找的解决方案需要适用于不同结构的表单/模型。范围内的模型是通过AJAX生成的,因此它们的结构已经设置好(我想避免必须为我已经通过AJAX接收到的所有数据硬编码新的结构)。另外,我希望在多个表单/模型之间使用此表单提交过程,并且每个表单/模型具有不同的JSON结构- 因为它们适用于我们的对象模型中的不同实体。这就是为什么我选择要求一种方法来访问controlsFormController中的对象(我将从FormController下面发布代码)的原因,因为这是我唯一可以获得所有字段的平面数组的地方。
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以便可以将该对象公开?还是创建一个公共函数,以便至少可以查看私有数组?
要直接解决该问题,请像这样修改@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”将包含脏的表单控件。
您还可以使用此技巧在提交表单时显示错误消息,以进行“必需”验证和所有其他验证。在您的commit()函数中,您将执行类似的操作;
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”或类似方法动态生成控件时,上述解决方案很有用。