Validazione dinamica del pattern ng di Angularjs


84

Ho un modulo che se una casella di controllo è falsa impone la convalida su un input di testo utilizzando la direttiva ng-required. Se la casella di controllo è true, il campo è nascosto e ng-required è impostato su false.

Il problema è che ho anche una regex per la convalida specificata nell'input e che utilizza la direttiva angolare ng-pattern. Il problema che sto riscontrando è che se un utente inserisce un numero di telefono non valido, seleziona la casella per disattivare tale input (e di conseguenza non necessita di ulteriore convalida) il modulo non consentirà l'invio in quanto non valido in base al modello ng.

Ho tentato di risolvere questo problema aggiungendo una funzione ng-change per impostare il modello di input su null, tuttavia il ng-pattern e quindi il campo è ancora impostato su non valido sul set iniziale della casella di controllo su false. Se tuttavia deseleziono la casella, reimpostando tutto sul caricamento del modulo iniziale, quindi spunto di nuovo la casella, il modulo è valido e può essere inviato. Non sono sicuro di cosa mi manchi. Ecco il codice ng-change che ho finora:

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

Risposte:


175

Questo è un problema interessante, convalida angolare complessa. Il seguente violino implementa ciò che desideri:

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

Dettagli

Ho creato una nuova direttiva, rpatternche è un mix di Angular ng-requirede il ng-patterncodice di input[type=text]. Quello che fa è guardare l' requiredattributo del campo e tenerne conto durante la convalida con regexp, cioè se non è obbligatorio, contrassegnare il campo come valid-pattern.

Appunti

  • La maggior parte del codice proviene da Angular, adattato alle esigenze di questo.
  • Quando la casella di controllo è selezionata, il campo è obbligatorio.
  • Il campo non è nascosto quando la casella di controllo richiesta è falsa.
  • L'espressione regolare è semplificata per la demo (valida è di 3 cifre).

Una soluzione sporca (ma più piccola), se non vuoi una nuova direttiva, sarebbe qualcosa del tipo:

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

E in HTML non sarebbero necessarie modifiche:

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

Questo in realtà induce angolare a chiamare il nostro test() metodo, invece di RegExp.test(), che prende requiredin considerazione.


2
Sarei molto interessato a sapere cosa fanno le parentesi tonde che circondano e dopo la funzione. Non funziona senza di loro
NeedHack

5
Chiamano direttamente la funzione, posizionando effettivamente il suo valore di ritorno alla variabile. È molto comune in Javascript per non inquinare uno scope esterno con dettagli di implementazione di un componente specifico, ad esempio guarda il pattern del modulo .
Nikos Paraskevopoulos

6
La soluzione sporca, fare un trucco su AngularJS basato sul "ducktyping" di JS è il codice più fantastico che ho visto oggi. Soluzione davvero intelligente!
Florian Loch

Grazie per il fantastico codice, ma ancora non molto chiaro, 1) secondo docs.angularjs.org/api/ng/directive/input , "Se l'espressione restituisce un oggetto RegExp, questo viene utilizzato direttamente. Se l'espressione valuta in una stringa, quindi verrà convertito in RegExp ", ma suppongo che phoneNumberPattern sia un oggetto quando ritorna? Questo dovrebbe essere un Regxp Obj? 2) E nella funzione (value) {} store in test, da dove viene il parametro "value"? Apprezzo per eventuali risposte!
user2499325

1
1) La clausola "Se l'espressione restituisce RegExp" viene implementata da Angular controllando se la cosa che ottiene ha un testmetodo. Questo è il motivo per cui gli diamo un oggetto con la nostra personalizzazione test(), essenzialmente emulando un JS nativo RegExp. 2) valueOvviamente Angular viene passato durante l'esecuzione del controllo di validità effettivo.
Nikos Paraskevopoulos

25

Non togliendo nulla alla fantastica risposta di Nikos, forse puoi farlo più semplicemente:

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

Presta attenzione al secondo input: possiamo usare un ng-ifper controllare il rendering e la convalida nei moduli. Se la requireTelvariabile non è impostata, il secondo input non solo verrà nascosto, ma non verrà visualizzato affatto, quindi il modulo passerà la convalida e il pulsante verrà abilitato e otterrai ciò di cui hai bisogno.


1
Il lato positivo è semplice. Lo svantaggio, qualsiasi input che viene rimosso quando l'espressione ng-if è false, avrà del testo rimosso se ng-if viene quindi valutato come true in seguito. Tuttavia, +1 per semplicità.
Brad

Volevo aggiungere, se segui questa strada, assicurati di capire che tutto all'interno di ng-if (se lo metti su un div per esempio) ora avrà il proprio ambito.
Brad

5

Modello utilizzato:

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

File di riferimento utilizzato:

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

Esempio di input:

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

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


2

Mi sono imbattuto in questo l'altro giorno.

Quello che ho fatto, che sembra più facile di quanto sopra, è impostare il pattern su una variabile dell'ambito e fare riferimento ad esso in ng-pattern nella vista.

Quando "la casella di controllo è deselezionata" ho semplicemente impostato il valore regex su /.*/ sul callback onChanged (se deselezionato). ng-pattern seleziona quel cambiamento e dice "OK, il tuo valore va bene". Il modulo è ora valido. Vorrei anche rimuovere i dati errati dal campo in modo da non avere un telefono apparentemente cattivo # seduto lì.

Ho avuto ulteriori problemi con ng-required e ho fatto la stessa cosa. Ha funzionato come un fascino.


0

Imposta la chiave di errore di convalida del modello se ngModel $ viewValue non corrisponde a una RegExp trovata valutando l'espressione angolare fornita nel valore dell'attributo. Se l'espressione restituisce un oggetto RegExp, questo viene utilizzato direttamente. Se l'espressione restituisce una stringa, verrà convertita in una RegExp dopo averla racchiusa tra ^ e $ caratteri.

Sembra che una risposta più votata a questa domanda dovrebbe essere aggiornata, perché quando la provo, non applica la testfunzione e la convalida non funziona.

L'esempio di documenti Angular funziona bene per me:

Modifica dei validatori incorporati

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


-1

Puoi usare il sito https://regex101.com/ per creare il tuo modello specifico per alcuni paesi:

Ad esempio, la Polonia:

-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}"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.