Получение элементов управления FormController
Мне нужен способ прокрутки зарегистрированных элементов формы AngularJS. По сути, я пытаюсь получить все грязные элементы управления, но нет массива элементов управления (у FormController есть несколько различных свойств/функций в дополнение к содержанию самих элементов управления, каждый из которых является его собственным объектом).
Я смотрел исходный код, и я вижу, что в FormController есть массив controls
, который точно соответствует массиву, который я ищу. Есть ли способ получить доступ к этому значению или расширить FormController, чтобы включить функцию, которая возвращает этот массив controls
?
Изменить: Plnkr demo
Кроме того, я понял, что технически я могу проверить первый символ в ключевой строке для "$", но я бы хотел этого избежать, если формация FormController/директива изменится в будущей версии Angular.
Изменить 2: Еще одно уточнение. Моя цель заключается в том, чтобы определить, какие конкретные поля являются "грязными", путем циклического перебора всего списка элементов управления (не считая $dirty, $invalid, $error, $name и другие свойства, которые живут в объекте Form как есть) или путем расширения FormController и создания функции, которая возвращает только те элементы управления, которые в настоящее время загрязнены (и не равны их начальным значениям)
Изменить 3: Решение, которое я ищу, должно быть применимо к формам/моделям разных структур. Модели в области сгенерированы с помощью AJAX, поэтому их структура уже установлена (я бы хотел избежать жесткой кодировки новой структуры для всех данных, которые я уже получаю через AJAX). Кроме того, я хочу использовать этот процесс подачи формы для нескольких форм/моделей, и каждый из них имеет разные структуры JSON - поскольку они применяются к различным объектам в нашей объектной модели. Вот почему я решил попросить способ получить доступ к объекту controls
в 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
, чтобы я мог сделать этот объект общедоступным? Или создать публичную функцию, чтобы я мог хотя бы просмотреть частный массив?
Ответы
Ответ 1
Для прямого решения вопроса, измените @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" или что-то подобное.
Ответ 2
Вы можете использовать следующий код для итерации элементов управления:
var data = {};
angular.forEach(myForm, function (value, key) {
if (value.hasOwnProperty('$modelValue'))
data[key] = value.$modelValue;
});
Ответ 3
попробуйте просто с вашего контроллера:
$scope.checkForm = function(myFormName){
console.log(myFormName.$invalid);
}
UPDATE:
<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);
}
});
Ответ 4
Я придумал несколько приличное решение, но все еще не то, что я искал. Я избавил некоторый код от другой проблемы, связанной с созданием объектов JSON из строк, и придумал следующее:
По сути, я называю свои поля так же, как они привязаны к модели, а затем создает новый объект для представления при вызове form_submit.
Демо-версия Plnkr
В демоверсии, если вы измените любое из полей формы, нажмите "отправить", вы увидите, что объект всплывает только с грязными значениями.