I need a way to loop through the registered controls of an AngularJS form. Essentially, I'm trying to get all the $dirty controls, but there's no array of the controls (the FormController has a number of different properties/functions in addition to containing the controls themselves - each as its' own object).
I've been looking at the source code, and I see that there is a controls
array in the FormController that is exactly the array I'm looking for. Is there a way to get access to this value, or extend the FormController to include a function that returns this controls
array?
Edit: Plnkr demo
Also, I realized that technically I could check the first character in the key string for "$", but I'd like to avoid that in case the FormController/directive changes in a future version of Angular.
Edit 2: Another clarification: My goal in all of this is to be able to determine which specific fields are $dirty, whether by looping through the entire list of controls (not including the $dirty, $invalid, $error, $name, and other properties that live in the Form object as it is) or by extending the FormController and creating a function that returns only the controls which are currently dirty (and not equal to their starting values)
Edit 3: The solution I'm looking for needs to be applicable to forms/models of different structures. The models on the scope are generated via AJAX, so their structure is already set (I'd like to avoid having to hardcode a new structure for all the data I'm already receiving via AJAX). Also, I'm looking to use this form submission process across multiple forms/models, and each of them have differing JSON structures - as they apply to different entities in our Object Model. This is why I've chosen to ask for a way to get access to the controls
object in the FormController (I'll post the code from FormController
below), because it's the only place where I can get a flat array of all of my fields.
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
}
As you can see, the form itself has the controls
array privately available. I'm wondering if there's a way for me to extend the FormController
so I can make that object public? Or create a public function so I can at least view the private array?