This is a step by step guide for Server Side form validations with AngularJS and Rails backend
Most of the information comes from the following article but I add some important information that was left out:
Server Form Validation with Angular.js
We will start with the form:
<form name="yourForm" ng-submit="addPost()" novalidate>
<input type="text" name="title" ng-model="newPost.title" server-error />
<!--take note the name attribute must be the exact same as the attribute name in your rails model -->
<span class="errors" ng-show="yourForm.title.$dirty && yourForm.title.$invalid">
<span ng-show="yourForm.title.$error.server">{{errors.title}}</span>
</span>
<input type="text" name="content" ng-model="newPost.content" server-error />
<span class="errors" ng-show="yourForm.content.$dirty && yourForm.content.$invalid">
<span ng-show="yourForm.content.$error.server">{{errors.content}}</span>
</span>
<input type="submit" />
</form>
The "novalidate" turns off the in-browser HTML5 validations which we dont want for Angular and the "server-error" makes a call to our directive that we will be making next.
Next we will create the directive that waits for input change then invalidates the server error until submission again:
angular.module('yourApp').directive('serverError', function(){
return {
restrict: 'A',
require: '?ngModel',
link: function(scope,element,attrs,ctrl){
return element.on('change keyup', function(){
return scope.$apply(function(){
return ctrl.$setValidity('server', true);
});
});
}
};
});
Now we will add the functionality to your controller:
angular.module('yourApp').controller('PostCtrl', function($scope, PostService) {
$scope.addPost = function() {
var error, success, newPost;
newPost = $scope.newPost;
$scope.errors = {}; //clean up previous server errors
success = function(result) {
//things to do if it returns success, here is my example code, will likely be different for you
$scope.posts.unshift(result);
$scope.newPost = {};
};
error = function(result) {
angular.forEach(result.data.errors, function(errors, field) {
$scope.yourForm[field].$setValidity('server', false);
$scope.errors[field] = errors.join(', ');
});
};
// if you are using $http in your server do this
// return PostService.create(post).then(success, error);
// otherwise if you are using $resource in your service do this
// return PostService.save(post).$promise.then(success, error);
};
});
Lastly we will change your models Rails Controller so that it returns the errors as json:
module Api
module V1
class PhrasesController < ApplicationController
respond_to :json
#other code.....
def create
@phrase = Phrase.new(phrase_params)
@phrase.save
respond_with @phrase, location: "" #this is the part where is returns the success or returns errors with the response
end
def create
@phrase = Phrase.find(params[:id])
@phrase.update(phrase_params)
respond_with @phrase, location: "" #this is the part where is returns the success or returns errors with the response
end
#more code.....
end
end
end
Basically this is what respond_with does automatically
if @phrase.save
render json: @phrase, status: 200
else
render json: {errors: @phrase.errors}, status: 422
end
You now have server side validation! Congrats!