web-dev-qa-db-fra.com

Attribut de nom de formulaire dynamique <input type = "text" name = "{{nom-variable}}" /> dans Angularjs

Comment une personne utiliserait-elle formName.inputName. $ Valide quand le "inputName" a été créé dynamiquement?

  <form name="formName">
    <input ng-repeat="(variable) in variables"
           type="text" name="variable.name"
           ng-model="variable.name" required />
 </form>

La sortie de l'attribut d'entrée HTML 'name' serait la chaîne "variablename", qui s'appliquerait à TOUTES les entrées répétées.

Si on essayait ça

<form name="formName">
  <input ng-repeat="(variable) in variables"
         type="text" name="{{ variable.name }}"
         ng-model="variable.name" required />
</form>

La sortie de l'attribut d'entrée HTML 'name' serait la chaîne "{{variable.name}}", qui serait appliquée à TOUTES les entrées répétées.

Dans l'une ou l'autre de ces conditions, un attribut de nom pour chacun des éléments d'entrée répétés ne serait pas créé de manière dynamique. TOUTES les entrées partageraient le même nom d’entrée. Pas très bon si vous voulez appeler une entrée spécifique basée sur un nom spécifique.

  • besoin d'utiliser des valeurs de nom dynamiques
  • avoir besoin d'appeler $ scope.formName.dynamicName. $ valid
  • besoin d'appeler $ scope.formName. $ valid
  • nécessite l'ajout de champs de saisie de nom dynamique à un formulaire imbriqué ou un formulaire maître
23
SoEzPz

Je ne pouvais pas trouver la réponse qui répondait à tout ou partie de ces besoins. C'est ce que je suis venu avec. 

Il y a peut-être un meilleur moyen, alors s'il vous plaît, partagez vos pensées.
J'utilise Angularjs 1.3.0-beta.8

J'ai un formulaire avec des directives multi-imbriquées contenant toutes des entrées, des sélections, etc., ces éléments sont tous entourés de ng-repeats et de valeurs de chaîne dynamiques.

Voici comment utiliser la directive:

<form name="myFormName">
  <nested directives of many levels>
    ex: <input ng-repeat=(index, variable) in variables" type="text"
               my-name="{{ variable.name + '/' + 'myFormName' }}"
               ng-model="variable.name" required />
    ex: <select ng-model="variable.name" ng-options="label in label in {{ variable.options }}"
                my-name="{{ variable.name + '/' + 'myFormName' }}"
        </select>
</form>

Remarque: vous pouvez ajouter et indexer la concaténation de chaînes si vous devez sérialiser éventuellement une table d'entrées. c'est ce que j'ai fait. Cependant, les entrées de nom dynamiques signifient que vous ne connaissez peut-être pas le nom de l'entrée de formulaire. Comment appelez-vous donc $ scope.formName. ??????. Vous pouvez effectuer une itération de l'objet $ scope.formName pour obtenir les clés correspondant à une certaine valeur. Cela signifie une concaténation de chaînes comme celle-ci:

my-name="{{ dynamicString + hello + '/' + 'myFormName' }}"

Ensuite, dans $ scope.myFormName, vous trouverez tout nom d’entrée de formulaire en effectuant une simple itération sur l’objet et en rassemblant toutes les clés contenant «hello».

app.directive('myName', function(){

  var myNameError = "myName directive error: "

  return {
    restrict:'A', // Declares an Attributes Directive.
    require: 'ngModel', // ngModelController.

    link: function( scope, elem, attrs, ngModel ){
      if( !ngModel ){ return } // no ngModel exists for this element

      // check myName input for proper formatting ex. something/something
      checkInputFormat(attrs);

      var inputName = attrs.myName.match('^\\w+').pop(); // match upto '/'
      assignInputNameToInputModel(inputName, ngModel);

      var formName = attrs.myName.match('\\w+$').pop(); // match after '/'
      findForm(formName, ngModel, scope);
    } // end link
  } // end return

  function checkInputFormat(attrs){
    if( !/\w\/\w/.test(attrs.rsName )){
      throw myNameError + "Formatting should be \"inputName/formName\" but is " + attrs.rsName
    }
  }

  function assignInputNameToInputModel(inputName, ngModel){
    ngModel.$name = inputName
  }

  function addInputNameToForm(formName, ngModel, scope){
    scope[formName][ngModel.$name] = ngModel; return
  }

  function findForm(formName, ngModel, scope){
    if( !scope ){ // ran out of scope before finding scope[formName]
      throw myNameError + "<Form> element named " + formName + " could not be found."
    }

    if( formName in scope){ // found scope[formName]
      addInputNameToForm(formName, ngModel, scope)
      return
    }
    findForm(formName, ngModel, scope.$parent) // recursively search through $parent scopes
  }
});

Cela devrait gérer de nombreuses situations où vous ne savez tout simplement pas où sera le formulaire. Ou peut-être avez-vous des formulaires imbriqués, mais pour une raison quelconque, vous souhaitez associer ce nom d'entrée à deux formulaires? Eh bien, transmettez simplement le nom du formulaire auquel vous souhaitez associer le nom de l’entrée.

Ce que je voulais, c’était un moyen d’affecter des valeurs dynamiques à des entrées que je ne saurai jamais, puis d’appeler simplement $ scope.myFormName. $ Valid.

Cela peut être exagéré, et une meilleure solution existe dans la version 1.3+. Je ne pouvais pas le trouver dans le temps dont je disposais. Cela fonctionne pour moi maintenant.

Bonne chance! J'espère que cela aide quelqu'un !!!

2
SoEzPz

On dirait que Angular 1.3 a résolu ce problème ( https://stackoverflow.com/a/32907176/3854385 )

Ceci est maintenant possible avec Angular 1.3+:

<form name="vm.myForm" novalidate>
  <div ng-repeat="p in vm.persons">
    <input type="text" name="person_{{$index}}" ng-model="p" required>
    <span ng-show="vm.myForm['person_' + $index].$invalid">Enter a name</span>
  </div>
</form>

Démo

Dans certains cas, un formulaire interne est une bonne solution si vous pouvez simplement transmettre les informations: ( https://stackoverflow.com/posts/12044600/ ) Pour résoudre le problème du 'nom dynamique' vous besoin de créer une forme interne (voir ng-form ):

<div ng-repeat="social in formData.socials">
      <ng-form name="urlForm">
            <input type="url" name="socialUrl" ng-model="social.url">
            <span class="alert error" ng-show="urlForm.socialUrl.$error.url">URL error</span>
            <button ng-click="doSomething(urlForm.socialUrl.$valid)">Test</button>
      </ng-form>
  </div>

L'autre alternative serait d'écrire une directive personnalisée pour cela.

Voici le jsFiddle montrant l'utilisation du ngForm: http://jsfiddle.net/pkozlowski_opensource/XK2ZT/2/

20
Loren

travaille pour moi avec angular 1.2.7

directif:

var DynamicName = function() {
    return {
        restrict: 'A',
        priority: -1,
        require: ['ngModel'],
        link: function (scope, element, attr, ngModel) {
            ngModel[0].$name = attr.name;
        }
    };
};

app.directive('dynamicName', DynamicName);

comment utiliser:

<div ng-repeat="phone in hrModel.phones">
    <input type="text"
           name="phones[{{$index}}]"
           ng-model="phones[$index]"
           dynamic-name
    />
</div>
0
ahiipsa