var app = angular.module('demo', ['jp.ng-bs-animated-button']);


app.controller('formCtrl', function($scope, $timeout) {

	$scope.isSubmit = false;
	$scope.isComplete = false;
	
  $scope.fakeSubmit = function() {
    $scope.isSubmit = true;
    $timeout(function(){
      $scope.isComplete = true;
    }, 500);
  };

});

<!DOCTYPE html>
<html ng-app="demo">

  <head>
    <meta charset="utf-8" />
    <title>ng-bs-animated-button demo</title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />    
    <link rel="stylesheet" href="ng-bs-animated-button.css" />          
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
    <script src="ng-bs-animated-button.js"></script>    
    <script src="app.js"></script>
  </head>

  <body>

      <form name="demoSuccessForm" role="form" ng-controller="demoSubmitSuccessCtrl" ng-submit="fakeSubmit()" style="margin:20px;">
        <jp-ng-bs-animated-button progress-is-submit="isSubmit" result-is-success="isSuccess" result-is-error="isError" animation-complete-time="1000" button-default-class="btn-primary" button-error-class="btn-danger" button-text="Click for success" form-is-invalid="demoSuccessForm.$invalid"></jp-ng-bs-animated-button>
      </form>
      
      <form name="demoErrorForm" role="form" ng-controller="demoSubmitErrorCtrl" ng-submit="fakeSubmit()" style="margin:20px;">
        <jp-ng-bs-animated-button progress-is-submit="isSubmit" result-is-success="isSuccess" result-is-error="isError" animation-complete-time="1000" button-default-class="btn-primary" button-error-class="btn-danger" button-text="Click for error" form-is-invalid="demoErrorForm.$invalid"></jp-ng-bs-animated-button>
      </form>      
    
  </body>

</html>
@-webkit-keyframes btn-ng-bs-rotation {
    0% {
        -webkit-transform: rotate(0);
        transform: rotate(0);
    }
    100% {
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}
@-moz-keyframes btn-ng-bs-rotation {
    0% {
        -moz-transform: rotate(0);
        transform: rotate(0);
    }
    100% {
        -moz-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}
@-o-keyframes btn-ng-bs-rotation {
    0% {
        -o-transform: rotate(0);
        transform: rotate(0);
    }
    100% {
        -o-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}
@keyframes btn-ng-bs-rotation {
    0% {
        transform: rotate(0);
    }
    100% {
        transform: rotate(360deg);
    }
}
.btn-ng-bs-animated .icons {
  opacity: 0;
  width: 0;
  -webkit-transition: opacity 0.25s, width 0.25s;
  -moz-transition: opacity 0.25s, width 0.25s;
  -o-transition: opacity 0.25s, width 0.25s;
  transition: opacity 0.25s, width 0.25s;
}
.btn-ng-bs-animated.is-active .icons {
  opacity: 1;
  width: 13px;
  margin-right: 10px;
}
.btn-ng-bs-animated.is-active .icons .icon-spinner {
  -webkit-animation: btn-ng-bs-rotation 2s infinite linear;
  -moz-animation: btn-ng-bs-rotation 2s infinite linear;
  -o-animation: btn-ng-bs-rotation 2s infinite linear;
  animation: btn-ng-bs-rotation 2s infinite linear;  
}
angular.module('jp.ng-bs-animated-button', []).
  directive('jpNgBsAnimatedButton', function($timeout) {
    return {
      restrict: 'AE',
      replace: true,
      scope: {
        progressIsSubmit: '=',
        resultIsSuccess: '=',
        resultIsError: '=',        
        formIsInvalid: '=',
        animationCompleteTime: '@',
        buttonDefaultClass: '@',
        buttonErrorClass: '@',        
        buttonText: '@'
      },
      template:
        '<button type="submit" class="btn {{buttonDefaultClass}} btn-ng-bs-animated clearfix" ng-disabled="formIsInvalid">' +
          '<div class="icons pull-left">' +
            '<span class="glyphicon glyphicon-refresh icon-spinner icon-submit hidden"></span>' +
            '<span class="glyphicon glyphicon-ok icon-result icon-success hidden"></span>' +
            '<span class="glyphicon glyphicon-remove icon-result icon-error hidden"></span>' +            
          '</div>' +
          '<div class="text pull-right">{{buttonText}}</div>' +
        '</button>',
      link: function(scope, element) {
        var el = angular.element(element);
        var iconSubmitting = angular.element(el[0].querySelector('.icon-submit'));
        var iconResult = angular.element(el[0].querySelectorAll('.icon-result'));
        var iconSuccess = angular.element(el[0].querySelector('.icon-success'));
        var iconError = angular.element(el[0].querySelector('.icon-error'));    
        var endAnimation = function() {
          el.removeClass('is-active').attr('disabled', false);
          iconResult.addClass('hidden');
          scope.resultIsSuccess = false;
          scope.resultIsError = false;          
        };
        scope.$watch('progressIsSubmit', function(newValue) {
            if (newValue) {
              el.attr('disabled', true).addClass('is-active');
              iconSubmitting.removeClass('hidden');
            }
          }, true).bind(this);
        scope.$watch('resultIsSuccess', function(newValue) {
            if (newValue) {
              iconSubmitting.addClass('hidden');
              iconSuccess.removeClass('hidden');
              scope.progressIsSubmit = false;
              $timeout(endAnimation, scope.animationCompleteTime);
            }
          }, true).bind(this);
        scope.$watch('resultIsError', function(newValue) {
            if (newValue) {
              iconSubmitting.addClass('hidden');
              iconError.removeClass('hidden');
              scope.progressIsSubmit = false;
              $timeout(endAnimation, scope.animationCompleteTime);
            }
          }, true).bind(this);          
      }
    };
  });