Réconcilier le style de validation de forme Angular.js et Bootstrap

J’utilise Angular avec Bootstrap. Voici le code de référence:

Bootstrap a des styles pour les champs invalides sous la forme d’ input:invalid {.... } ; ceux-ci interviennent lorsque le champ est vide. Maintenant, j’ai aussi une correspondance de motif via Angular. Cela crée des cas particuliers lorsque “: invalide” est désactivé, mais que “.ng-invalide” est activé, ce qui nécessiterait de ré-implémenter les classes CSS bootstrap pour la classe “.ng-invalide”.

Je vois deux options, mais avoir des problèmes avec les deux

  • Faites qu’Angular utilise un nom de classe personnalisé au lieu de “ng-valide” (je ne sais pas comment faire).
  • Désactiver la validation html5 (je pensais que c’était ce que l’atsortingbut “novalidate” dans la balise de formulaire devrait faire, mais ne pouvait pas le faire fonctionner pour une raison quelconque).

Les directives Angular-Bootstrap ne couvrent pas le style.

Utilisez la classe “error” de Bootstrap pour le style. Vous pouvez écrire moins de code.

 
Required

EDIT: Comme d’autres réponses et commentaires le font remarquer – dans Bootstrap 3, la classe est maintenant “has-error”, pas “error”.

Les classes ont changé dans Bootstrap 3:

 

please enter your email

please enter a valid email

...

Notez les citations autour de 'has-error' et 'has-success' : il a fallu du temps pour trouver que …

Une autre solution: créer une directive qui bascule has-error classe has-error fonction d’une entrée enfant.

 app.directive('bsHasError', [function() { return { ressortingct: "A", link: function(scope, element, attrs, ctrl) { var input = element.find('input[ng-model]'); if (input.length) { scope.$watch(function() { return input.hasClass('ng-invalid'); }, function(isInvalid) { element.toggleClass('has-error', isInvalid); }); } } }; }]); 

puis utilisez-le simplement dans le modèle

 

Amélioration mineure de la réponse de @ farincz . Je suis d’accord qu’une directive est la meilleure approche ici, mais je ne voulais pas devoir la répéter sur chaque élément .form-group , donc j’ai mis à jour le code pour permettre de l’append au groupe .form-group ou au

parent

élément (qui l’appenda à tous les éléments contenus .form-group ):

 angular.module('directives', []) .directive('showValidation', [function() { return { ressortingct: "A", link: function(scope, element, attrs, ctrl) { if (element.get(0).nodeName.toLowerCase() === 'form') { element.find('.form-group').each(function(i, formGroup) { showValidation(angular.element(formGroup)); }); } else { showValidation(element); } function showValidation(formGroupEl) { var input = formGroupEl.find('input[ng-model],textarea[ng-model]'); if (input.length > 0) { scope.$watch(function() { return input.hasClass('ng-invalid'); }, function(isInvalid) { formGroupEl.toggleClass('has-error', isInvalid); }); } } } }; }]); 

Amélioration mineure de la réponse de @Andrew Smith. Je change les éléments de saisie et utilise require mot-clé require .

 .directive('showValidation', [function() { return { ressortingct: "A", require:'form', link: function(scope, element, attrs, formCtrl) { element.find('.form-group').each(function() { var $formGroup=$(this); var $inputs = $formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]'); if ($inputs.length > 0) { $inputs.each(function() { var $input=$(this); scope.$watch(function() { return $input.hasClass('ng-invalid'); }, function(isInvalid) { $formGroup.toggleClass('has-error', isInvalid); }); }); } }); } }; }]); 

Merci à @farincz pour une excellente réponse. Voici quelques modifications que j’ai apscopes à mon cas d’utilisation.

Cette version fournit trois directives:

  • bs-has-success
  • bs-has-error
  • bs-has (une commodité pour quand vous voulez utiliser les deux autres ensemble)

Modifications que j’ai apscopes:

  • Ajout d’une vérification pour afficher uniquement les états a lorsque le champ de formulaire est sale, c’est-à-dire qu’ils ne seront pas affichés tant que quelqu’un n’interagira pas avec eux.
  • Modification de la chaîne passée à element.find() pour ceux qui n’utilisent pas jQuery, car element.find() dans jQLite d’Angular ne supporte que la recherche d’éléments par tagname.
  • Ajout du support pour les boîtes de sélection et les zones de texte.
  • Emballé le element.find() dans un $timeout pour prendre en charge les cas où l’élément n’a pas encore rendu ses enfants au DOM (par exemple, si un enfant de l’élément est marqué avec ng-if ).
  • Modification de l’expression if pour vérifier la longueur du tableau renvoyé ( if(input) from @ farincz’s answer renvoie toujours true, car le retour de element.find() est un tableau jQuery).

J’espère que quelqu’un trouve cela utile!

 angular.module('bs-has', []) .factory('bsProcessValidator', function($timeout) { return function(scope, element, ngClass, bsClass) { $timeout(function() { var input = element.find('input'); if(!input.length) { input = element.find('select'); } if(!input.length) { input = element.find('textarea'); } if (input.length) { scope.$watch(function() { return input.hasClass(ngClass) && input.hasClass('ng-dirty'); }, function(isValid) { element.toggleClass(bsClass, isValid); }); } }); }; }) .directive('bsHasSuccess', function(bsProcessValidator) { return { ressortingct: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-valid', 'has-success'); } }; }) .directive('bsHasError', function(bsProcessValidator) { return { ressortingct: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-invalid', 'has-error'); } }; }) .directive('bsHas', function(bsProcessValidator) { return { ressortingct: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-valid', 'has-success'); bsProcessValidator(scope, element, 'ng-invalid', 'has-error'); } }; }); 

Usage:

  

Vous pouvez également installer le package Bower de Guilherme qui regroupe tous ces éléments.

Si le problème est le style, mais que vous ne voulez pas désactiver la validation native, pourquoi ne pas remplacer le style par votre propre style, plus spécifique ?

 input.ng-invalid, input.ng-invalid:invalid { background: red; /*override any styling giving you fits here*/ } 

En cascade vos problèmes avec la spécificité du sélecteur CSS!

Mon amélioration de la réponse de Jason Im à la suite ajoute deux nouvelles directives show-validation-errors et show-validation-error.

 'use ssortingct'; (function() { function getParentFormName(element,$log) { var parentForm = element.parents('form:first'); var parentFormName = parentForm.attr('name'); if(!parentFormName){ $log.error("Form name not specified!"); return; } return parentFormName; } angular.module('directives').directive('showValidation', function () { return { ressortingct: 'A', require: 'form', link: function ($scope, element) { element.find('.form-group').each(function () { var formGroup = $(this); var inputs = formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]'); if (inputs.length > 0) { inputs.each(function () { var input = $(this); $scope.$watch(function () { return input.hasClass('ng-invalid') && !input.hasClass('ng-pristine'); }, function (isInvalid) { formGroup.toggleClass('has-error', isInvalid); }); $scope.$watch(function () { return input.hasClass('ng-valid') && !input.hasClass('ng-pristine'); }, function (isInvalid) { formGroup.toggleClass('has-success', isInvalid); }); }); } }); } }; }); angular.module('directives').directive('showValidationErrors', function ($log) { return { ressortingct: 'A', link: function ($scope, element, attrs) { var parentFormName = getParentFormName(element,$log); var inputName = attrs['showValidationErrors']; element.addClass('ng-hide'); if(!inputName){ $log.error("input name not specified!") return; } $scope.$watch(function () { return !($scope[parentFormName][inputName].$dirty && $scope[parentFormName][inputName].$invalid); },function(noErrors){ element.toggleClass('ng-hide',noErrors); }); } }; }); angular.module('friport').directive('showValidationError', function ($log) { return { ressortingct: 'A', link: function ($scope, element, attrs) { var parentFormName = getParentFormName(element,$log); var parentContainer = element.parents('*[show-validation-errors]:first'); var inputName = parentContainer.attr('show-validation-errors'); var type = attrs['showValidationError']; element.addClass('ng-hide'); if(!inputName){ $log.error("Could not find parent show-validation-errors!"); return; } if(!type){ $log.error("Could not find validation error type!"); return; } $scope.$watch(function () { return !$scope[parentFormName][inputName].$error[type]; },function(noErrors){ element.toggleClass('ng-hide',noErrors); }); } }; }); })(); 

Les show-validation-errors peuvent être ajoutés à un conteneur d’erreurs afin d’afficher / masquer le conteneur en fonction de la validité des champs de formulaire.

et show-validation-error affiche ou masque un élément basé sur cette validité des champs de formulaire sur un type donné.

Un exemple d’utilisation prévue:

  
Organization number is required.
Organization number needs to have the following format "000 000 000" or "000000000".

Je pense qu’il est trop tard pour répondre mais j’espère que vous allez l’aimer:

CSS, vous pouvez append d’autres types de contrôles comme select, date, password etc.

 input[type="text"].ng-invalid{ border-left: 5px solid #ff0000; background-color: #FFEBD6; } input[type="text"].ng-valid{ background-color: #FFFFFF; border-left: 5px solid #088b0b; } input[type="text"]:disabled.ng-valid{ background-color: #efefef; border: 1px solid #bbb; } 

HTML : pas besoin d’append quoi que ce soit dans les contrôles sauf ng-required si c’est

  

Essayez-le et tapez du texte dans votre contrôle, je le trouve très pratique et génial.

Il est difficile de dire avec certitude sans violon mais en regardant le code angular.js, il ne remplace pas les classes – il ajoute et supprime simplement les siennes. Donc, toutes les classes de bootstrap (ajoutées dynamicment par les scripts d’interface utilisateur de bootstrap) ne devraient pas être affectées par l’angle.

Cela dit, il n’est pas logique d’utiliser la fonctionnalité JS de Bootstrap pour la validation en même temps que l’utilisation angular. Je vous suggère d’utiliser les styles de bootstrap et le JS angular, c’est-à-dire d’append les classes css bootstrap à vos éléments en utilisant une directive de validation personnalisée.

 

Je sais que c’est un très vieux fil de réponse à la question quand je n’ai pas entendu le nom d’AngularJS lui-même 🙂

Mais pour ceux qui arrivent sur cette page à la recherche de la validation de formulaire Angular + Bootstrap de manière propre et automatisée, j’ai écrit un petit module pour obtenir le même résultat sans modifier le code HTML ou Javascript sous quelque forme que ce soit.

Validation de la validation angular du bootstrap .

Voici les trois étapes simples:

  1. Installer via Bower bower install bootstrap-angular-validation --save
  2. Ajoutez le fichier de script
  3. Ajoutez la dépendance bootstrap.angular.validation à votre application et c’est tout!

Cela fonctionne avec Bootstrap 3 et jQuery n’est pas requirejs .

Ceci est basé sur le concept de validation jQuery. Ce module fournit des validations supplémentaires et des messages génériques communs pour les erreurs de validation.