Comment afficher les erreurs de serveur dans Angularjs avec ng-messages

J'ai mon application angulaire validant un formulaire d'inscription. Lors de l'envoi, le serveur valide également les données. Je génère des messages d'erreur dans angular en utilisant ng-messages.

Voici une version raccourcie de mon formulaire, qui fonctionne parfaitement jusqu'à présent.

<form name="signUpForm" novalidate data-ng-submit="attemptSignUp()">
    <label for="firstName">First name</label>
    <input type="email" name="email" id="email" required data-ng-model="data.user.email" />
    <div class="error" data-ng-messages="signUpForm.email.$error" data-ng-show="signUpForm.$submitted" data-ng-cloak>
        <p data-ng-message="required">Please provide your email</p>
    </div>
</form>

Le serveur vérifie que l'adresse e-mail est unique, et sinon, renvoie une erreur 422 (de Laravel 5), avec un tableau d'erreurs.

[
    'email' => 'This email is already in use'
]

Je voudrais fusionner ceci, et tous les autres messages renvoyés du serveur dans leur bloc ng-messages pertinent. Une idée de comment je pourrais l'accomplir?

21
demandé sur Leon 2015-01-26 22:32:48

4 réponses

Une solution simple consiste à avoir deux tableaux. Un pour les erreurs côté client et un pour les erreurs côté serveur qui est rempli dans votre contrôleur. Vous pouvez masquer les erreurs côté serveur si des erreurs client existent ou s'opposent pour éviter les doubles messages.

La raison pour laquelle je choisis d'avoir deux tableaux au lieu de remplir le tableau forms est que le contrôleur JavaScript ne doit pas connaître ou dépendre de la structure du HTML. Le modèle HTML AngularJS doit être lié au contrôleur, pas vis vis.

<form name="signUpForm" novalidate data-ng-submit="attemptSignUp()">
    <label for="email">E-mail
        <input type="email" name="email" id="email" required data-ng-model="data.user.email" />
        <div class="error" data-ng-messages="signUpForm.email.$error" data-ng-show="signUpForm.$submitted" data-ng-cloak>
            <p data-ng-message="required">Please provide your email</p>
        </div>
        <div class="error" data-ng-messages="serverErrors" data-ng-show="signUpForm.$submitted" data-ng-cloak>
            <p data-ng-message="emailexists">Email already exists</p>
        </div>
    </label
</form>

Une note sur l'étiquette: les utilisateurs utilisant des lecteurs d'écran ne recevront pas vos messages d'erreur lus à haute voix s'ils ne sont pas enveloppés dans l'étiquette.

27
répondu jornare 2017-01-18 07:36:09

Eh Bien, ce n'est pas la solution la plus élégante puisque vous devriez vraiment tirer parti des asyncValidators dans angular 1.3.x puis créez votre directives de validation personnalisées.

Ressources

Http://plnkr.co/edit/s4jJAOqehBkFUC9osMsy?p=preview trouvé dans le post de cette guy.

Peut-être ici http://odetocode.com/blogs/scott/archive/2014/10/16/working-with-validators-and-messages-in-angularjs.aspx

Et bien sûr dans les documents

Mais soyez prudent, comme ce n'est en aucun cas un exemple complet prêt à être utilisé. C'est surtout ici à des fins de démonstration et pour vous donner une idée par où commencer. Je n'ai pas pris la peine d'Effacer les erreurs précédentes, de revalider le formulaire ou de prendre en compte d'autres erreurs de validation.

Awesomeness

Imaginez votre contrôleur ressemble à ça

$scope.serverValidations = {};
$scope.attemptSignUp = function(){

    Api.validateEmail($scope.email).then(angular.noop, function(data){

      $scope.serverValidations = data
      for(prop in $scope.serverValidations){
          if($scope.signUpForm[prop]){
            angular.forEach($scope.serverValidations[prop],function(validation){
                $scope.signUpForm[prop].$setValidity(validation.type, false);
            });
          }
      }
    });
}

Et vos données de réponse contenant les erreurs de validation ressemblent à ceci

{
  email:[
     {type:'unique', message:'This email is already in use'}
  ],
  name:[
     {type:'maxlength', message:'Your name is to long, get a new one :)'}
  ]
};

Ensuite, dans votre HTML, vous pouvez faire comme ceci

<div class="error" data-ng-messages="signUpForm.name.$error" data-ng-cloak="">
    <p data-ng-message="required">You don't have a name?</p>
    <p ng-repeat="validation in serverValidations['name']" ng-message="{{validation.type}}">{{validation.message}}</p>
</div>

Voici un Codepen sale pour vous: http://codepen.io/anon/pen/yyzMgG?editors=101 Lorsque vous appuyez sur soumettre, après 2 secondes (le temps qu'il faut pour frapper le faux serveur) vos validations de serveur sont présentés.

8
répondu mengstrom 2015-02-02 19:17:35

Tout d'Abord, vous devez définir validity et error messages

      $scope.formErrors = {};
      angular.forEach(errors, function(data, name) {
        if (!vm.register_form[name]) {
          return;
        }
        $scope.formErrors[name] = data.message;
        //this will set errors->server to invalid state
        $scope.register_form[name].$setValidity('server', false);
      });

L'étape suivante sera le rendu par ng-messages

      <div ng-messages="register_form.email.$error">
        <div ng-message="required">Email is required</div>
        <div ng-message="email">Invalid email</div>
        <div ng-message="server">{{formErrors.email}}</div>
      </div>
6
répondu Artyom Trityak 2015-02-02 19:22:24

J'ai eu une question similaire, mais les solutions n'ont pas fonctionné pour moi. Ce que j'ai fait, et c'est/était un hack/work around, était d'envoyer différents errorcodes, et de définir une déclaration de cas.

-5
répondu Greg P 2015-02-02 15:49:31