0

Binding values with $scope.minutes = 1 to ng-bind="minutes" not working when I add scope: {finishcallback: "&"}, to my directive.

I'm trying to implement a countdown timer with Angular directives but cannot set the value of the remaining minute and second to the child span element when I define a scope function in the directive.

<time id="countdown_{{order.Id}}" ng-if="order.StatusCode == 1" countdown="{{order.RemainingTimeToPrepareOrder}}" finishcallback="vm.countdownfinished(parameter)" callbackparameter="{{order.Id}}" countdownfinished="toggle()">                                        
  <b> <span class="value" ng-bind="minutes"></span>  dakika   <span class="value" ng-bind="seconds">--</span> saniye</b>
</time>

And here is my directive code.

function countdown() {
    return {
        restrict: 'A', 
        scope: {
            finishcallback: "&"
        },
        controller: function ($scope, $attrs, $timeout) {

            $attrs.$observe('countdown', function (value) {
                var ds = new Date();
                ds.setTime(value * 1000);

                $scope.days = '-';
                $scope.hours = $scope.minutes = $scope.seconds = '--';

                $scope.timeout = $timeout(update, 1000);

                function update() {
                    now = +new Date();

                    $scope.delta = Math.round((ds - now) / 1000);
                    if ($scope.delta >= 0) {
                        $timeout(update, 1000);
                    } else if ($attrs.countdownfinished) {
                        $scope.$apply($attrs.countdownfinished);
                    }
                }
            });
        },
        link: function ($scope, $element, $attrs) {
            $scope.$watch('delta', function (delta) {
                if (typeof delta === 'undefined') return;

                if (delta < 0) {
                    delta = 0;
                }

                $scope.days = Math.floor(delta / 86400);
                $scope.hours = forceTwoDigits(Math.floor(delta / 3600) % 24);
                $scope.minutes = forceTwoDigits(Math.floor(delta / 60) % 60);
                $scope.seconds = forceTwoDigits(delta % 60);
            });
            $scope.toggle = function () {
                $scope.finishcallback({ parameter: $attrs.callbackparameter });
            }
            function forceTwoDigits(num) {
                return String(num < 10 ? '0' + num : num);
            }

        }
    }
}

All the functionality is working until I add finishcallback: "&" scope variable in my directive. I added this to enable custom function calls when the countdown finished. But when I add this my assignments like $scope.minutes stopped to change values in my spans.

How do I change span values dynamically even I define a scope in my directive ?

3
  • wrong tag.. please change angular to angularjs :) Commented Oct 13, 2020 at 8:34
  • Is it because you forgot the quotes around "{{order.RemainingTimeToPrepareOrder}}"? Commented Oct 13, 2020 at 8:55
  • Nope. It is not a problem. my main problem is ng-bind="minutes" not working when I add scope: { finishcallback: "&" }, to my directive. @RubenHelsloot Commented Oct 13, 2020 at 9:01

1 Answer 1

0

I'd recommend to just use a template:

function countdown($timeout) {
  return {
    restrict: 'A',
    scope: {
      finishcallback: "&"
    },
    template: `<b> <span class="value" ng-bind="minutes"></span>  dakika   <span class="value" ng-bind="seconds">--</span> saniye</b>`,
    controller: function($scope, $attrs) {

      $attrs.$observe('countdown', function(value) {
        var ds = new Date();
        ds.setTime(value * 1000);

        $scope.days = '-';
        $scope.hours = $scope.minutes = $scope.seconds = '--';

        $scope.timeout = $timeout(update, 1000);

        function update() {
          now = +new Date();

          $scope.delta = Math.round((ds - now) / 1000);
          if ($scope.delta >= 0) {
            $timeout(update, 1000);
          } else if ($attrs.countdownfinished) {
            $scope.$apply($attrs.countdownfinished);
          }
        }
      });
    },
    link: function($scope, $element, $attrs) {
      $scope.$watch('delta', function(delta) {
        if (typeof delta === 'undefined') return;

        if (delta < 0) {
          delta = 0;
        }

        $scope.days = Math.floor(delta / 86400);
        $scope.hours = forceTwoDigits(Math.floor(delta / 3600) % 24);
        $scope.minutes = forceTwoDigits(Math.floor(delta / 60) % 60);
        $scope.seconds = forceTwoDigits(delta % 60);
      });
      $scope.toggle = function() {
        $scope.finishcallback({
          parameter: $attrs.callbackparameter
        });
      }

      function forceTwoDigits(num) {
        return String(num < 10 ? '0' + num : num);
      }

    }
  }
}

angular.module('app', [])
  .controller('ctrl', function($scope, $interval) {
    $scope.order = {
      Id: 1,
      StatusCode: 1,
      RemainingTimeToPrepareOrder: Date.now() + 5 * 60 * 1000,
    };
    $scope.countdownfinished = function(parameter) {
      console.log(parameter);
    }
    $scope.toggle = function() {
      console.log("Toggle");
    }

    $interval(function() {
      $scope.order.RemainingTimeToPrepareOrder -= 1000;
    }, 1000);
  })
  .directive('countdown', countdown);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <time id="countdown_{{order.Id}}" ng-if="order.StatusCode == 1" countdown="{{order.RemainingTimeToPrepareOrder}}" finishcallback="countdownfinished(parameter)" callbackparameter="{{order.Id}}" countdownfinished="toggle()"> 
</time>
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.