web-dev-qa-db-fra.com

Obtention des contrôles de formulaire à partir de FormController

J'ai besoin d'un moyen de parcourir les contrôles enregistrés d'un formulaire AngularJS. Essentiellement, j'essaie d'obtenir tous les contrôles $ dirty, mais il n'y a pas de tableau des contrôles (le FormController a un certain nombre de propriétés/fonctions différentes en plus de contenir les contrôles eux-mêmes - chacun comme son propre objet).

J'ai regardé le code source et je vois qu'il y a un tableau controls dans FormController qui est exactement le tableau que je recherche. Existe-t-il un moyen d'accéder à cette valeur ou d'étendre le FormController pour inclure une fonction qui renvoie ce tableau controls?

Modifier: Plnkr démo

De plus, j'ai réalisé que techniquement, je pouvais vérifier le premier caractère de la chaîne de clé pour "$", mais j'aimerais éviter cela au cas où la directive FormController/changerait dans une future version d'Angular.

Edit 2: Une autre clarification: Mon objectif dans tout cela est de pouvoir déterminer quels champs spécifiques sont $ dirty, que ce soit en parcourant la liste entière des contrôles (sans inclure les $ dirty, $ invalid, $ error, $ name, et d'autres propriétés qui vivent dans l'objet Form tel quel) ou en étendant FormController et en créant une fonction qui renvoie uniquement les contrôles qui sont actuellement sales (et non égaux à leurs valeurs de départ)

Edit 3: La solution que je recherche doit être applicable aux formes/modèles de différentes structures. Les modèles sur l'oscilloscope sont générés via AJAX, donc leur structure est déjà définie (je voudrais éviter d'avoir à coder en dur une nouvelle structure pour toutes les données que je reçois déjà via AJAX). De plus, je cherche à utiliser ce processus de soumission de formulaire sur plusieurs formulaires/modèles, et chacun d'eux a des structures JSON différentes - car elles s'appliquent à différentes entités de notre modèle d'objet. C'est pourquoi j'ai choisi de demander un moyen d'accéder à l'objet controls dans le FormController (je posterai le code de FormController ci-dessous), car c'est le seul endroit où Je peux obtenir un tableau plat de tous mes domaines.

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
}

Comme vous pouvez le voir, le formulaire lui-même a le tableau controls disponible en privé. Je me demande s'il y a un moyen pour moi d'étendre le FormController pour que je puisse rendre cet objet public? Ou créer une fonction publique afin que je puisse au moins afficher le tableau privé?

29
robert.bo.roth

Pour une solution directe à la question, modifiez la réponse de @ lombardo comme ceci;

     var dirtyFormControls = [];
     var myForm = $scope.myForm;
     angular.forEach(myForm, function(value, key) {
         if (typeof value === 'object' && value.hasOwnProperty('$modelValue') && value.$dirty)
             dirtyFormControls.Push(value)                        
     });

Le tableau "dirtyFormControls" contiendra alors les contrôles de formulaire qui sont sales.

Vous pouvez également utiliser cette astuce pour afficher des messages d'erreur lors de la soumission du formulaire pour les validations "requises" et toutes les autres. Dans votre fonction submit (), vous ferez quelque chose comme;

 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;
 }

Et dans votre formulaire, vous afficherez des messages d'erreur avec

    <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>

La solution ci-dessus est utile lorsque vous avez généré des contrôles générés dynamiquement en utilisant 'ng-repeat' ou quelque chose de similaire.

19
faitha

Vous pouvez utiliser le code suivant pour itérer les contrôles:

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

essayez simplement avec depuis votre contrôleur:

$scope.checkForm = function(myFormName){
     console.log(myFormName.$invalid);
}

MISE À JOUR:

<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);
                }
        });
2
Whisher

J'ai trouvé une solution quelque peu décente, mais ce n'est toujours pas ce que je cherchais . J'ai récupéré du code d'un autre problème impliquant la création d'objets JSON à partir de chaînes et j'ai trouvé ce qui suit:

Essentiellement, je nomme mes champs de la même manière qu'ils sont liés au modèle, puis je crée un nouvel objet à soumettre lorsque le form_submit est appelé.

démo Plnkr

Dans la démo, si vous modifiez l'un des champs du formulaire, puis cliquez sur soumettre, vous verrez l'objet surgir avec uniquement les valeurs sales.

0
robert.bo.roth