28

Мне нужен способ прокрутки зарегистрированных элементов формы AngularJS. По сути, я пытаюсь получить все $ dirty элементы управления, но нет массива элементов управления (у FormController есть несколько различных свойств/функций в дополнение к содержанию самих элементов управления, каждый из которых является его собственным объектом).Получение элемента управления формы от FormController

Я смотрел исходный код, и я вижу, что в FormController есть массив controls, который является именно тем массивом, который я ищу. Есть ли способ получить доступ к этому значению или расширить FormController, чтобы включить функцию, которая возвращает этот массив controls?

Edit: Plnkr демо

Кроме того, я понял, что технически я мог проверить первый символ в ключевой строке для «$», но я хотел бы избежать, что в случае 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, чтобы я мог сделать этот объект общедоступным? Или создать публичную функцию, чтобы я мог, по крайней мере, просматривать частный массив?

+0

У вас нет моделей, связанных с элементами управления? Вы можете просто наблюдать за моделями, чтобы увидеть, изменились ли они, а не прокручивать элементы управления формы. –

+0

У меня есть модели, я просто стараюсь избегать делать часы, потому что в директиве Form уже есть часы, чтобы обрабатывать все грязные проверки, а для больших форм это может выполняться медленно :( –

+0

Хороший вопрос, это то же самое Я ищу (моя цель - остановить проверку на отправке после появления первой ошибки). В это время вы нашли альтернативное решение, лучше, чем проверка на первый символ ($)? – Fernando

ответ

18

Для непосредственного решения вопроса, изменить ответ @ Ломбардо как так;

 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> 

выше решение полезно, когда вы динамически элементы управления с помощью «нг-повтор» или что-то подобное.

+0

Я полностью забыл, что я представил этот вопрос, и в итоге сделал что-то очень похожее на то, что вы разместили здесь. Я на самом деле закончил расширение директивы ngSubmit, чтобы он выполнил весь мой код проверки для ВСЕХ моих

элементов, которые имеют функции ngSubmit. –

+0

Надеюсь, что эта проблема решена, не мешая вам! Использование директив, вероятно, является лучшим способом создания пользовательских материалов в AngularJS, но есть много встроенных продуктов, которые можно использовать. – faitha

+0

Просто позаботьтесь о ng-форме. Этот метод не обрабатывает их. – user1067920

2

попробовать просто с внутри контроллера:

$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); 
       } 
     }); 
+0

Я не думаю, что мой вопрос был ясен, поэтому я добавил демонстрационную версию plnkr. У меня нет проблем с обнаружением, если форма $ грязная или $ недействительная Моя проблема в том, что у меня нет хорошего способа прокрутки всех элементов управления формой (сами поля), чтобы определить, какие конкретные поля являются «грязными». Моя основная цель - отправить только те поля, которые были отредактированы. –

+0

Я обновил свой ответ – Whisher

+0

Это в значительной степени то, что у меня есть на данный момент, но моя проблема в том, что мне нужно перебирать неструктурированный/многомерный объект JSON в моем объеме, поэтому я бы предпочел чтобы иметь возможность прокручивать плоский массив полей, находящихся в 'FormController' –

0

Я придумал несколько приличном решение, но оно все еще не то, что я искал для. Я избавил некоторый код от другой проблемы, связанной с созданием объектов JSON из строк, и придумал следующее:

По сути, я назову свои поля так же, как они привязаны к модели, а затем построил новый объект для представления при вызове form_submit.

Plnkr demo

В демке, если изменить одно из полей формы, затем нажмите отправить, вы увидите объект всплывал только грязные ценности.

11

Вы можете использовать следующий код для перебора элементов управления:

var data = {}; 
    angular.forEach(myForm, function (value, key) { 
     if (value.hasOwnProperty('$modelValue')) 
      data[key] = value.$modelValue; 
    }); 
+8

, мне пришлось добавить' typeof value === 'object' && 'в ваше условие if. В противном случае вы можете получить такие ошибки, как «TypeError: Невозможно прочитать свойство hasOwnProperty» неопределенного « –

+0

@BryanLarsen. Лучше использовать angular.isObject (значение) для этого. Он также проверяет нулевые значения, потому что 'typeof null' также является объектом. –

Смежные вопросы