У меня есть секундомер с разными заголовками, когда я запускаю часы, они запускаются, и через 10 секунд появляется предупреждение. Я могу фильтровать часы поверх заголовка, когда я сбрасываю фильтр, работающие часы не отображают время, но они появляются оповещение через 10 секунд. Почему привязка не работает после фильтра? Что здесь не так? Как это исправить? Найдите плункер здесь. Полный код и HTML находятся в плункере.

Нажатие на воспроизведение запустит часы, пауза приостановит их, а стоп - остановит часы.

< script type = "text/javascript" > angular.module('App', [])
        .controller('MainCtrl', function ($scope, $interval) {
        $interval(function () {
            $scope.sharedTime = new Date();
        }, 500);
    })
        .directive('stopwatch', function () {
        return {
            restrict: 'AE',
            templateUrl: 'stopwatch.html',
            scope: {
                // Set title in the isolate scope from the title attribute on the     directive's element.
                title: '@title',
                // Set up a bi-directional binding between currentTime on the local scope and the parent
                // scope's variable containing the current time that's the value of the time attribute.
                currentTime: '=time'
            },
            link: function (scope, element, attrs, ctrl) {},
            controllerAs: 'swctrl',
            controller: function ($scope, $interval) {
                var self = this;
                var time = 0;
                var mode = 1;
                var status = 0;
                var timer_id;
                self.play = 1;
                self.start = function (interval) {
                    self.play = 0;
                    var timeRet;
                    interval = 1000;
                    if (status == 0) {
                        status = 1;

                        function timeRun() {
                            if (time < 86400) {
                                time++;
                                timeRet = self.getElapsedMs();
                                if (time == 10) {
                                    alert("Its 10 seconds")
                                }

                                if (typeof (callback) === 'function') callback(timeRet);
                            }
                        };
                        return timer_id = setInterval(timeRun, interval);
                    }

                };

                self.pause = function () {
                    self.play = 1;
                    if (status == 1) {
                        status = 0;
                        clearInterval(timer_id);
                    }
                };

                self.stop = function () {
                    self.play = 1;
                    sec = (typeof (sec) !== 'undefined') ? sec : 0;
                    time = sec;
                    if (status == 1) {
                        status = 0;
                        clearInterval(timer_id);
                    }


                };

                self.getTime = function () {
                    return time;
                };



                self.getElapsedMs = function () {

                    var second = time % 60;
                    var minute = Math.floor(time / 60) % 60;
                    var hour = Math.floor(time / 3600) % 60;

                    second = (second < 10) ? '0' + second : second;
                    minute = (minute < 10) ? '0' + minute : minute;
                    hour = (hour < 10) ? '0' + hour : hour;

                    var timeObj = hour + ":" + minute + ":" + second

                    return timeObj;
                };
            }
        }
    }); < /script>

Как воспроизвести: активируйте один, затем введите «два» в текстовое поле, а затем сотрите его. Вы увидите, что один таймер показывает 00:00:00.

0
mithu 15 Апр 2015 в 10:59
Мне кажется нормально. Пауза/Воспроизведение и Стоп/Воспроизведение увеличивают секунды и показывают предупреждение через 10 секунд.
 – 
camden_kid
15 Апр 2015 в 11:25
Я тоже не заметил в начале. Попробуйте активировать one, затем введите «два» в текстовом поле и сотрите его. Вы увидите, что таймер one показывает 00:00:00.
 – 
Omri Aharon
15 Апр 2015 в 11:29
Да я вижу. Возможно, стоит поместить свой комментарий в вопрос.
 – 
camden_kid
15 Апр 2015 в 11:31

2 ответа

Фильтр в ng-repeat применяет ваше ключевое слово фильтрации к массиву и возвращает новое подмножество, тем самым уничтожая ранее созданные директивы.

Из документов:

Выбирает подмножество элементов из массива и возвращает его как новый массив.

Если вы поместите внутри функции ссылки:

scope.$on("$destroy", function () {
    console.log("destroying");
});

Вы увидите, что он регистрирует каждый секундомер, который исключается из-за фильтрации.

Поэтому я бы просто скрыл весь div секундомера вместо использования фильтра:

<div  ng-show="!filter || title.indexOf(filter) > -1">
    <div class="timer" >{{title}}<br>
       {{swctrl.getElapsedMs() | limitTo:6}}<span class="sec">
       {{swctrl.getElapsedMs() | limitTo:-2}}</span>

   </div>
  <a href="" ng-show ="swctrl.play" id="timerPlay" class="play" ng-click="swctrl.start();"> Play</a>
  <a href=""  ng-show ="!swctrl.play" id="timerPause" class="pause"  ng-click="swctrl.pause();">Pause</a>
  <a href=""  id="timerStop" class="stop" ng-click="swctrl.stop();" >Stop</a>    
</div>

И ваше использование становится:

<div ng-repeat="item in arr">
     <div stopwatch title="{{item}}" filter="filters" time="sharedTime">
</div>

Plunker

0
Omri Aharon 15 Апр 2015 в 11:26

Омри Аарон объяснил, в чем проблема. Лично я бы переместил функцию секундомера на фабрику и передал бы ее экземпляры в вашу директиву.

.factory('StopWatch', function() {
    function StopWatch(name) {
      this.name = name;
      this.time = 0;
      this.mode = 1;
      this.status = 0;
      this.play = 1;
    }

    StopWatch.prototype.start = function(interval) {

      var self = this;
      self.play = 0;

      var timeRet;


      interval = 1000;  
      if(self.status == 0)
      {
        self.status = 1;
        function timeRun()
        {       
            if(self.time < 86400)
            {
              self.time++;
              timeRet =  self.getElapsedMs();
              if(self.time == 10)
              {
                alert("Its 10 seconds")
              }

              if(typeof(callback) === 'function') callback(timeRet);
            }               
        };
        return self.timer_id = setInterval(timeRun, interval);     
      }

    };

    StopWatch.prototype.pause = function() {
      this.play = 1;
      if(this.status == 1)
      {
        this.status = 0;
        clearInterval(this.timer_id);
      }
    };

    StopWatch.prototype.stop = function() {
      this.play = 1;
      var sec = (typeof(sec) !== 'undefined') ? sec : 0;
      this.time = sec;
      if(this.status == 1)
      {
        this.status = 0;
        clearInterval(this.timer_id);
      }
    };

    StopWatch.prototype.getTime = function() {
      return this.time;
    };

    StopWatch.prototype.getElapsedMs = function() {

      var second = this.time % 60;
      var minute = Math.floor(this.time / 60) % 60;
      var hour = Math.floor(this.time / 3600) % 60;

      second = (second < 10) ? '0'+second : second;
      minute = (minute < 10) ? '0'+minute : minute;
      hour = (hour < 10) ? '0'+hour : hour;

      var timeObj = hour+":"+minute+":"+second

      return timeObj;

    };

    return StopWatch;
})

Итак, вы бы создали секундомеры:

$scope.timers = [
  new StopWatch('one'),
  new StopWatch('two'),
  new StopWatch('three'),
  new StopWatch('four')
];

Затем повторите и перейдите в директиву:

<div ng-repeat="item in timers | filter:filter_">
  {{item.name}}
  <div stopwatch="item"></div>
</div>

Plunker

0
noj 15 Апр 2015 в 12:41