Validation dynamique des ng-pattern angularjs

84

J'ai un formulaire qui, si une case à cocher est fausse, applique la validation sur une entrée de texte à l'aide de la directive ng-required. Si la case à cocher est true, le champ est masqué et le ng-required est défini sur false.

Le problème est que j'ai également une expression régulière pour la validation spécifiée sur l'entrée, utilisant également la directive angulaire ng-pattern. Le problème que je rencontre est que si un utilisateur remplit un numéro de téléphone invalide, coche la case pour désactiver cette entrée (et n'a donc pas besoin de validation supplémentaire), le formulaire ne permettra pas la soumission car il est invalide en fonction du modèle ng.

J'ai tenté de résoudre ce problème en ajoutant une fonction ng-change pour définir le modèle d'entrée sur null, mais le ng-pattern et donc le champ sont toujours définis sur invalide sur l'ensemble initial de la case à cocher sur false. Si je décoche cependant la case, remettant tout au chargement initial du formulaire, puis cochez à nouveau la case, le formulaire est valide et peut être soumis. Je ne suis pas sûr de ce qui me manque. Voici le code ng-change que j'ai jusqu'à présent:

    var phoneNumberRegex = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    $scope.phoneNumberPattern = phoneNumberRegex;
    $scope.removeValidation = function() {
        if ($scope.cell._newUser === false) {
            $scope.request._number = '';
            $scope.phoneNumberPattern = /[0-9a-zA-Z]?/;
        } else {
            $scope.phoneNumberPattern = phoneNumberRegex;
        }
    };
Brian
la source

Réponses:

175

Il s'agit d'un problème intéressant, complexe de validation angulaire. Le violon suivant met en œuvre ce que vous voulez:

http://jsfiddle.net/2G8gA/1/

Détails

J'ai créé une nouvelle directive, rpatternqui est un mélange d'Angular ng-requiredet du ng-patterncode de input[type=text]. Ce qu'il fait, c'est surveiller l' requiredattribut du champ et en tenir compte lors de la validation avec regexp, c'est-à-dire s'il n'est pas obligatoire, marquer le champ comme valid-pattern.

Remarques

  • La plupart du code provient d'Angular, adapté aux besoins de celui-ci.
  • Lorsque la case est cochée, le champ est obligatoire.
  • Le champ n'est pas masqué lorsque la case à cocher requise est fausse.
  • L'expression régulière est simplifiée pour la démo (valide à 3 chiffres).

Une solution sale (mais plus petite), si vous ne voulez pas de nouvelle directive, serait quelque chose comme:

$scope.phoneNumberPattern = (function() {
    var regexp = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    return {
        test: function(value) {
            if( $scope.requireTel === false ) {
                return true;
            }
            return regexp.test(value);
        }
    };
})();

Et en HTML, aucune modification ne serait requise:

<input type="text" ng-model="..." ng-required="requireTel"
    ng-pattern="phoneNumberPattern" />

Cela incite en fait angular à appeler notre test() méthode, au lieu de RegExp.test()prendre requireden compte le.

Nikos Paraskevopoulos
la source
2
Je serais très intéressé de savoir ce que font les parenthèses autour et après la fonction. Cela ne fonctionne pas sans eux
NeedHack
5
Ils appellent la fonction directement, plaçant effectivement sa valeur de retour dans la variable. Il est très courant en Javascript de ne pas polluer une portée externe avec les détails d'implémentation d'un composant spécifique, par exemple, regardez le modèle du module .
Nikos Paraskevopoulos
6
La solution sale, jouer un tour sur AngularJS basé sur le "ducktyping" de JS est le code le plus impressionnant que j'ai vu aujourd'hui. Solution vraiment intelligente!
Florian Loch du
Merci pour le code génial, mais toujours pas très clair, 1) selon docs.angularjs.org/api/ng/directive/input , "Si l'expression s'évalue en un objet RegExp, alors cela est utilisé directement. Si l'expression évalue à une chaîne, alors il sera converti en un RegExp ", mais je suppose que phoneNumberPattern est un objet lors du retour? Est-ce censé être un Obj Regxp? 2) Et dans la fonction (valeur) {} store in test, d'où vient le paramètre "valeur"? Merci pour toutes les réponses!
user2499325
1
1) La clause "Si l'expression évalue à RegExp" est implémentée par Angular en vérifiant si l'objet qu'il obtient a une testméthode. C'est pourquoi nous lui donnons un objet avec notre propre coutume test(), émulant essentiellement un JS natif RegExp. 2) Le valueest bien sûr passé par Angular lors de l'exécution du contrôle de validité réel.
Nikos Paraskevopoulos
25

Sans rien enlever à l'impressionnante réponse de Nikos, vous pouvez peut-être le faire plus simplement:

<form name="telForm">
  <input name="cb" type='checkbox' data-ng-modal='requireTel'>
  <input name="tel" type="text" ng-model="..." ng-if='requireTel' ng-pattern="phoneNumberPattern" required/>
  <button type="submit" ng-disabled="telForm.$invalid || telForm.$pristine">Submit</button>
</form>

Faites attention à la deuxième entrée: nous pouvons utiliser un ng-ifpour contrôler le rendu et la validation dans les formulaires. Si la requireTelvariable n'est pas définie, la deuxième entrée ne sera pas seulement masquée, mais pas du tout rendue, ainsi le formulaire passera la validation et le bouton deviendra activé, et vous obtiendrez ce dont vous avez besoin.

Kumarharsh
la source
1
L'avantage, c'est simple. L'inconvénient, toutes les entrées qui sont supprimées lorsque l'expression ng-if est fausse auront tout texte qu'elles contiennent supprimé si ng-if est ensuite évalué à vrai plus tard. Pourtant, +1 pour la simplicité.
Brad
Je voulais ajouter, si vous suivez cette voie, assurez-vous de bien comprendre que tout ce qui se trouve dans le ng-if (si vous le mettez sur un div par exemple) aura désormais sa propre portée.
Brad
5

Modèle utilisé:

 ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"

Fichier de référence utilisé:

 '<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>'

Exemple d'entrée:

 <input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">
Anil Singh
la source
2

 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
<input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">

Jijo Paulose
la source
2

Je viens de rencontrer ça l'autre jour.

Ce que j'ai fait, ce qui semble plus facile que ce qui précède, est de définir le modèle sur une variable de la portée et d'y faire référence dans ng-pattern dans la vue.

Lorsque "la case à cocher est décochée", je règle simplement la valeur de l'expression régulière sur /.*/ sur le rappel onChanged (si elle n'est pas cochée). ng-pattern choisit qui change et dit "OK, votre valeur est bonne". Le formulaire est maintenant valide. Je supprimerais également les mauvaises données du terrain afin que vous n'ayez pas un mauvais téléphone # apparemment assis là.

J'ai eu des problèmes supplémentaires autour de ng-required, et j'ai fait la même chose. A travaillé comme un charme.

jessewolfe
la source
0

Définit la clé d'erreur de validation de modèle si le ngModel $ viewValue ne correspond pas à un RegExp trouvé en évaluant l'expression angulaire donnée dans la valeur d'attribut. Si l'expression correspond à un objet RegExp, cela est utilisé directement. Si l'expression correspond à une chaîne, elle sera convertie en RegExp après l'avoir encapsulée en caractères ^ et $.

Il semble que la réponse la plus votée à cette question devrait être mise à jour, car lorsque je l'essaye, elle n'applique pas la testfonction et la validation ne fonctionne pas.

L'exemple de la documentation Angular fonctionne bien pour moi:

Modifier les validateurs intégrés

html

<form name="form" class="css-form" novalidate>
  <div>
   Overwritten Email:
   <input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
   <span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
   Model: {{myEmail}}
  </div>
</form>

js

var app = angular.module('form-example-modify-validators', []);

app.directive('overwriteEmail', function() {
    var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;

    return {
        require: 'ngModel',
        restrict: '',
        link: function(scope, elm, attrs, ctrl) {
            // only apply the validator if ngModel is present and Angular has added the email validator
            if (ctrl && ctrl.$validators.email) {

                // this will overwrite the default Angular email validator
                ctrl.$validators.email = function(modelValue) {
                    return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
                };
             }
         }
     };
 });

Plunker

theodor
la source
-1

Vous pouvez utiliser le site https://regex101.com/ pour créer votre propre modèle spécifique pour certains pays:

Par exemple, Pologne:

-pattern = xxxxxxxxx OR xxx-xxx-xxx OR xxx xxx xxx 
-regexp ="^\d{9}|^\d{3}-\d{3}-\d{3}|^\d{3}\s\d{3}\s\d{3}"
Lepton
la source