pardie
pardie

Reputation: 509

my AngularJS Spinner directive fails

I just wrote this simple directive to show a spinner on my button while something remote is happening: http://plnkr.co/edit/rAJ4X7A3iidmqUD2M63A?p=preview

html:

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

    <head>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script src="script.js"></script>
    </head>

    <body ng-controller="myController as vm">

        <button ng-click="vm.saveAction()" class="btn btn-primary" type="button">
            <!-- Original template -->

            <i class="fa fa-floppy-o" ng-hide="vm.save"></i>
            <i class="fa fa-circle-o-notch fa-spin ng-hide" ng-show="vm.save"></i> Save

            <!-- end -->
        </button>

        <button ng-click="vm.removeAction()" class="btn btn-default" type="button">
            <!-- Desired template (directive) -->

            <i my-spinner="vm.remove" icon="fa fa-trash"></i> Remove

            <!-- end -->
        </button>

    </body>

</html>

js:

app = angular.module('app', []);

app.controller('myController', ['$timeout', function($timeout) {
    var vm = this;

    vm.save = false;
    vm.remove = false;

    vm.saveAction = function() {
              vm.save = true;

              // ...save something remote

              $timeout(function() { // <-- simulate an async callback or whatever...
                vm.save = false;
              }, 3000);
    };

      vm.removeAction = function() {
              vm.remove = true;

              // ...remove something remote

              $timeout(function() { // <-- simulate an async callback or whatever...
                  vm.remove = false;
              }, 3000);
    };
}]);

app.directive('mySpinner', function() {
    var directive = {
        restrict: 'A',
        scope: {
            mySpinner: '@',
            icon: '@'
        },
        template: '<i class="{{icon}}" ng-hide="{{mySpinner}}"></i>' +
                  '<i class="fa fa-circle-o-notch fa-spin ng-hide" ng-show="{{mySpinner}}"></i>',
    };

    return directive;
});

I decided to use this solution based on ng-show and ng-hide so I haven't to $observe/$watch nothing in my directive... The html from the directive seems right but when I press on the Remove button nothing happens. Someone could help me? Thank you very much!

Upvotes: 0

Views: 169

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136144

You need to pass the value of mySpinner using =(two way binding) instead of @(one way binding), The reason behind this is, as you using @ means you will pass value through attribute with interpolation {{}} directive, which will eventually converts bool to string and the ng-show expression value will always become true.

The other reason behind it was not working is you were using {{}} interpolation in ng-show & ng-hide directive.

Directive

app.directive('mySpinner', function() {
  var directive = {
    restrict: 'A',
    scope: {
      mySpinner: '=',
      icon: '@'
    },
    template: '<i class="{{icon}}" ng-hide="mySpinner"></i>' +
      '<i class="fa fa-circle-o-notch fa-spin ng-hide" ng-show="mySpinner"></i>',
  };
  return directive;
});

You could refactor you template to use ng-class instead of using ng-show & ng-hide by applying classes conditionally.

template: '<i ng-class="mySpinner ? \'fa fa-circle-o-notch fa-spin=\': icon"></i>'

Update PLunkr

Upvotes: 1

Related Questions