Luciano Borges
Luciano Borges

Reputation: 827

How show validation messages from REST service on screen with AngularJS?

I have a controller like this:

(function() {
'use strict';

angular
    .module('app.bookmark')
    .controller('BookmarkEdit', BookmarkEdit);

function BookmarkEdit(BookmarkService, $stateParams, $state) {

    var vm = this;
    vm.bookmark = {};
    vm.save = save;

    function save() {
        BookmarkService.insert(vm.bookmark).success(saveOk).error(saveFail);
    }

    /* Callbacks */

    // I ommited the saveOk method!

    function saveFail(data, status, headers, config){
        switch(status){
            case 401:   console.log('401');
                        break;

            case 422:   console.log('422');
                        angular.forEach(data, function(value, key){
                         // THE CODE SHOULD COME HERE
                        });
                        break;
        }
    }

}})();

My service is like this:

(function() {
'use strict';

angular
    .module('app.bookmark')
    .factory('BookmarkService', BookmarkService);

function BookmarkService($http){

        var url = 'api/bookmark';

        BookmarkService.insert = function(bookmark){
            return $http.post(url, bookmark);
        };

        return BookmarkService;

}})();

If I send an empty form, my REST service makes its validations and return (RESPONSE) a JSON like this:

[
{property:description, message:required}
{property:link, message:maxlength}
]

I'd like to know how to show these messagens below of respective field?

Below follows my HTML code:

<form name="bookmarkForm class="well" role="form">

<div class="form-group">
    <label>ID: </label>
    <span id="id-text" class="form-control-static">{{bookmark.bookmark.id}}</span>
</div>

<div class="form-group">
    <label for="description">Description</label> 
    <input id="description" type="text" class="form-control" ng-model="bookmark.bookmark.description" value="{{bookmark.bookmark.description}}">
    <div id="description-message" class="label label-danger"><!-- the message should come here if exists --></div>
</div>

<div class="form-group">
    <label for="link">Link</label> 
    <input id="link" type="text" class="form-control" ng-model="bookmark.bookmark.link" value="{{bookmark.bookmark.link}}">
    <div id="link-message" class="label label-danger"><!-- the message should come here if exists --></div>
</div>

<div class="form-group">
    <button id="save" class="btn btn-primary" ng-click="bookmark.save()">Save</button>
</div>
</form>

EDIT

Looking for ngMessages, I change the DIV's for message to:

<div class="label label-danger" ng-messages="bookmarkForm.description.$error">
     <div ng-messages-include="templates/messages.html"></div>
</div>

And the messages.html file is like this:

<p ng-message="required" class="label label-danger">Required field</p>
<p ng-message="minlength" class="label label-danger">Few letters</p>
<p ng-message="manlength" class="label label-danger">Too much letters</p>
<p ng-message="url" class="label label-danger">Invalid URL</p>

I changed the controller to show the validations messages when necessary:

case 422:   angular.forEach(data, function(value, key){
              // I set the field invalid
              vm.bookmarkForm[value.property].$setValidity(value.message, false);
            });
            break;

Now the problem is that the previous validations messages remain on the screen after submitting the form again and change the content of this field so that it becomes valid, even though other fields in error.

How to clear these messages on the controller every time you send the form data?

Upvotes: 0

Views: 1717

Answers (3)

Luciano Borges
Luciano Borges

Reputation: 827

I solved this way:

case 422:
  angular.forEach(vm.bookmarkForm, function(value, i) {
    if (typeof value === 'object' && value.hasOwnProperty('$modelValue')) {
      vm.bookmarkForm[value.$name].$setValidity(Object.getOwnPropertyNames(value.$error)[0], true);
    }
  });

  angular.forEach(data, function(value, key) {
    vm.bookmarkForm[value.property].$setValidity(value.message, false);
  });
  break;

Upvotes: 0

Mike Feltman
Mike Feltman

Reputation: 5176

The easiest thing to do would be to assign the errors to members of your view model and then simply output those members in their respective divs.

Something like:

angular.forEach(data, function(value, key){
   if (value.property === "link") {
       vm.linkError = value.message; }
   else {
       vm.linkError = "" ;}
   if (value.property === "description") {
       vm.descriptionError = value.message; }
   else {
       vm.descriptionError = "" ;}

});

Not super elegant, but it would get the job done.

Upvotes: 1

Chris Story
Chris Story

Reputation: 1197

I highly recommend combining the use of ngMessages and some custom logic on the promise resolving to set the error states appropriately.

Here is a great example of the usage for ngMessages - http://www.yearofmoo.com/2014/05/how-to-use-ngmessages-in-angularjs.html

Upvotes: 1

Related Questions