У меня есть секундомер с разными заголовками, когда я запускаю часы, они запускаются, и через 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.
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>
Омри Аарон объяснил, в чем проблема. Лично я бы переместил функцию секундомера на фабрику и передал бы ее экземпляры в вашу директиву.
.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>
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript/JS) и его различных диалектах/реализациях (кроме ActionScript). Имейте в виду, что JavaScript — это НЕ то же самое, что Java! Включите все ярлыки, относящиеся к вашему вопросу; например, [node.js], [jQuery], [JSON], [ReactJS], [angular], [ember.js], [vue.js], [typescript], [svelte] и т. д.
one
, затем введите «два» в текстовом поле и сотрите его. Вы увидите, что таймерone
показывает 00:00:00.