I'm looking on how to make a 60 seconds countdown using angular js.
I want to show the countdown on the page ! and when the countdown is finished, the controller should reload to execute the code again ! and get the update json object !
my controller looks like :
.controller('todaymatches', function($rootScope,$scope, $http) {
$http.get("http://www.domaine.com/updatedjson/")
.success(function (response) {
$scope.matches = response;
});
})
I'm made a code ! I'm not sure if this works properly ! anyway it's not working on my app.
$scope.countdown = function() {
stopped = $timeout(function() {
console.log($scope.counter);
$scope.counter--;
$scope.countdown();
}, 1000);
};
Here is a simple countdown example:
HTML
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular-1.0.0rc11.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
</head>
<body>
<div ng-controller="CountdownController">
{{counter}}
</div>
</body>
</html>
Javascript
function CountdownController($scope,$timeout) {
$scope.counter = 60;
$scope.onTimeout = function(){
if ($scope.counter > 0) {
$scope.counter--;
mytimeout = $timeout($scope.onTimeout,1000);
} else {
$scope.counter = 60;
}
}
var mytimeout = $timeout($scope.onTimeout,1000);
}
Demo
'use strict';
var ngApp = angular.module('myApp', ['Test']);
var c1 = angular.module('Test', []);
c1.controller('Ctrl1', function ($scope, $timeout) {
$scope.coutDown = function () {
$scope.onTimeout = function () {
console.log("value", $scope.value);
$scope.value = $scope.value - 1;
return $scope.coutDown($scope.value);
};
var delay = $timeout($scope.onTimeout, 1000);
if ($scope.value < 1) {
$timeout.cancel(delay);
return true;
}
return false;
};
$scope.value = 5;
$scope.coutDown();
});
<div ng-app="myApp">
<div ng-controller="Ctrl1">
<h1>{{value}}</h1>
</div>
</div>
http://jsfiddle.net/pbxaD/49/
if you want to use $timeout you have to inject it. But why don't you just call the update method in a certain interval?
.controller('todaymatches', function($rootScope,$scope, $http, $interval) {
var update = function() {
$http.get("http://www.domaine.com/updatedjson/")
.success(function (response) {
$scope.matches = response;
});
};
var initialize = function() {
$interval(function() {
update();
}, 60 * 1000)
};
initialize();
})
I tried this for the count down and it seems to work.
app.controller('CountDownController', function($scope, $timeout) {
$scope.counter = 60;
$scope.countdown = function() {
if ($scope.counter === 0) {
// do your reload and execute here
//Just reset the counter if you just want it to count again
$scope.counter = 60;
return;
} else {
$timeout(function() {
console.log($scope.counter);
$scope.counter--;
$scope.countdown();
}, 1000);
}
};
$scope.countdown();
});
You could tie up the various things you want to do inside the if condition of the above code as commented. I just reset the counter after counting down to 0.
Related
I'm new in AngularJS and i'd like to know why, in the next piece of code, the "randomN" property of the service is not updating at the $scope.
Since i'm taking a reference to the object's service at the controller with
$scope.srvRandom = srvRandom;
Why changes at srvRandom.randomN are not taking effect?
I think the problem is that "randomN" takes the value of "r" and not a reference to it, but i don't know how to make it work.
var app = angular.module("app", []);
app.controller("cont", ['$scope','srvRandom', function ($scope, srvRandom) {
$scope.srvRandom = srvRandom;
}]);
app.factory("srvRandom", ["$interval", function ($interval) {
var randomCreator;
var r;
return {
start: function () {
console.log("START")
randomCreator = $interval(function () {
r= Math.random() * 10;
}, 2000);
},
stop: function () {
console.log("STOP")
$interval.cancel(randomCreator);
},
randomN: r
};
}]);
HTML:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.2/angular.min.js"></script>
<script src="test.js"></script>
</head>
<body ng-app="app" ng-controller="cont">
RandomNumber: {{srvRandom.randomN}}
<div>
<button ng-click="srvRandom.start()">START!</button>
<button ng-click="srvRandom.stop()">STOP!</button>
</div>
</body>
</html>
Thank you!
You are accessing srvRandom.randomN which is always 0.
...
randomN: 0
...
I think you should do
app.factory("srvRandom", ["$interval", function ($interval) {
var randomCreator,
randomN = 0; // Change
return {
start: function () {
console.log("START")
randomCreator = $interval(function () {
randomN = Math.random() * 10;
}, 2000);
},
stop: function () {
console.log("STOP")
$interval.cancel(randomCreator);
},
randomN: randomN // Change
};
}]);
just update your start method to use this for current object not window object.
start: function() {
var that = this; //store this reference to a variable
randomCreator = $interval(function() {
that.randomN = Math.random() * 10; // use here
}, 2000);
},
doing this $scope.Random = srvRandom; create a local instance of the service obj
var app = angular.module("app", []);
app.controller("cont", ['$scope', 'srvRandom',
function($scope, srvRandom) {
$scope.random = 0;
$scope.$watch('getRandom()',function(newv){
$scope.random = newv;
});
$scope.start = function(){
srvRandom.start();
}
$scope.stop = function(){
srvRandom.stop();
}
$scope.getRandom = function(){
return srvRandom.getRandom();
}
}
]);
app.factory("srvRandom", ["$interval",
function($interval) {
var randomCreator;
var randomN = 0;
return {
start: function() {
console.log("START")
randomCreator = $interval(function() {
randomN = Math.random() * 10;
}, 2000);
},
stop: function() {
console.log("STOP")
$interval.cancel(randomCreator);
},
getRandom: function() {
return randomN;
}
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app" ng-controller="cont">
RandomNumber: {{random}}
<div>
<button ng-click="start()">START!</button>
<button ng-click="stop()">STOP!</button>
</div>
</body>
I have this angularJS app which has a countdown timer. I want to execute a function after it becomes zero. It currently goes into negative after it reaches 0. How to achieve this?
Angular Code:
myApp.controller('MyController', ['$scope', '$timeout' ,function($scope, $http, $routeParams, $timeout) {
$scope.counter = 5000;
$scope.onTimeout = function(){
$scope.counter--;
mytimeout = $timeout($scope.onTimeout,1000);
}
var mytimeout = $timeout($scope.onTimeout,1000);
}
}]);
testControllers.filter('formatTimer', function() {
return function(input)
{
function z(n) {return (n<10? '0' : '') + n;}
var seconds = input % 60;
var minutes = Math.floor(input / 60);
var hours = Math.floor(minutes / 60);
return (z(hours) +':'+z(minutes)+':'+z(seconds));
};
});
HTML:
<div><p>{{counter|formatTimer}}</p></div>
Simply stop calling it when the counter is 0:
$scope.onTimeout = function(){
if (--$scope.counter > 0) {
$timeout($scope.onTimeout, 1000);
} else {
// Call your function now that counter is 0
}
}
Depending on what else you are doing, you probably don't need to put your timeout method on the scope. Also, look at $interval instead. It's better suited for calling something continuously.
function decreaseCounter() {
if(--$scope.counter <= 0) {
$interval.cancel(intervalPromise);
yourOtherFunction();
}
}
var intervalPromise = $interval(decreaseCounter, 1000);
https://docs.angularjs.org/api/ng/service/$interval
If you need a precise countdown (specially if the time span is large) you need to calculate the time spent using Date time function. Simply incrementing a counter each 1000 milliseconds 5000 times, doesen't guarantee that at the end, the real time spent will be exactly 5000 seconds!
You could try something like this:
Controller:
function MyCtrl($scope, $interval) {
var intervalId;
$scope.counter = 0;
$scope.initialCountdown = 10;
$scope.countdown = $scope.initialCountdown;
$scope.timer = function(){
var startTime = new Date();
intervalId = $interval(function(){
var actualTime = new Date();
$scope.counter = Math.floor((actualTime - startTime) / 1000);
$scope.countdown = $scope.initialCountdown - $scope.counter;
}, 1000);
};
$scope.$watch('countdown', function(countdown){
if (countdown === 0){
$scope.stop();
}
});
$scope.start = function(){
$scope.timer();
};
$scope.stop = function(){
$interval.cancel(intervalId);
};
}
View:
<div ng-controller="MyCtrl">
<div>Counter: {{counter}}</div>
<div>Countdown in seconds: {{countdown}}</div>
<div>Countdown date time: {{countdown | secondsToDateTime | date:'HH:mm:ss'}}</div>
<button ng-click="start()">start</button>
<button ng-click="stop()">stop</button>
</div>
Filter secondsToDateTime:
myApp.filter('secondsToDateTime', [function() {
return function(seconds) {
return new Date(1970, 0, 1).setSeconds(seconds);
};
}])
CHECK THE DEMO FIDDLE
Enjoy!
My directive with controller :
app.directive("photoGallery", function() {
return {
restrict: 'E',
templateUrl: 'part/photoGallery.html',
controller: ["$http", function($http) {
me = this;
this.autoSlide = true;
this.currentIndex = 2;
this.autoSlide_timer;
this.photos = [{}];
this.Show = function(index) {
me.currentIndex = index;
};
this.Next = function() {
me.currentIndex++;
console.log(me.currentIndex);
if (me.currentIndex >= me.photos.length) {
me.currentIndex = 0;
}
me.Show(me.currentIndex);
};
this.Prev = function() {
me.currentIndex--;
if (me.currentIndex < 0) {
me.currentIndex = me.photos.length-1;
}
me.Show(me.currentIndex);
};
this.Init = function() {
$http.get("img/slider/_data.json")
.success(function(data) {
me.photos = data;
for(var i in me.photos) {
me.photos[i].index = i;
}
console.info(me.photos);
})
.error(function(e){
console.error(e);
});
this.autoSlide_timer = setInterval(this.Next, 1500);
}();
}],
controllerAs: 'gallery'
};
});
photoGallery.html :
<div class="GalleryContainer">{{gallery.currentIndex}}
<div class="PhotoWrapper">
<div ng-repeat="photo in gallery.photos" class="photo" ng-class="{active:gallery.currentIndex == photo.index}">
<img ng-src="img/slider/{{photo.path}}">
</div>
</div>
</div>
as you can see, in the Next() function, I log currentIndex
Next() is called every 1500ms thanks to setInterval(this.Next, 1500) in the Init() function.
I can see in the console : 2, 3, 4, ... 10, 0, 1, 2 ...
But in the browser, {{gallery.currentIndex}} is never updated, it display the default value (2) (photoGallery.html line 1)
You have to use angular $interval() instead of JavaScript setInterval() function. Why ?
Because Angular needs to know when variables are updated. $interval make a call to $scope.$apply() at the end of its execution, executing a new $digest loop that notify the update to angular.
You can also wait the request to be successfully proceed to set you interval, to avoid errors.
this.Init = function() {
$http.get("img/slider/_data.json")
.success(function(data) {
me.photos = data;
for(var i in me.photos) {
me.photos[i].index = i;
}
console.info(me.photos);
me.autoSlide_timer = $interval(me.Next, 1500);
})
.error(function(e){
console.error(e);
});
}();
I coded the below directive for infinite scroll, my problem which I couldn't figure out why it just fire once when the directive is loaded, I need your advice on how to make my list infinite-scroll.
I'm using it to get data remotely and each time i'm calling it I add to the counter 25, so each time it would return more data.
Thanx,
angular.module('MyApp')
.controller('InboxCtrl', function($scope, InboxFactory) {
var counter = 0;
$scope.loadData = function() {
var promise = InboxFactory.getEvents(counter);
promise.then(function(result) {
$scope.events = result;
});
counter += 25;
};
});
angular.module('MyApp')
.factory('InboxFactory', function($http, $q) {
// Service logic
var defered = $q.defer();
function getUrl(count) {
return "api/inbox/get?request={'what':'Search','criteria':'inbox','criteriaId':null,'startTime':null,'endTime':null,'offset':" + count + ",'limit':25,'order':'event_time','direction':'DESC','source':''}";
}
function extract(result) {
return result.data.data;
}
// Public API here
return {
getEvents: function(count) {
$http.get(getUrl(count)).then(
function(result) {
defered.resolve(extract(result))
}, function(err) {
defered.reject(err);
}
);
return defered.promise;
}
};
});
angular.module('MyApp')
.directive('infiniteScroll', ['$timeout',
function(timeout) {
return {
link: function(scope, element, attr) {
var
lengthThreshold = attr.scrollThreshold || 50,
timeThreshold = attr.timeThreshold || 400,
handler = scope.$eval(attr.infiniteScroll),
promise = null,
lastRemaining = 9999;
lengthThreshold = parseInt(lengthThreshold, 10);
timeThreshold = parseInt(timeThreshold, 10);
if (!handler || !components.isFunction(handler)) {
handler = components.noop;
}
element.bind('scroll', function() {
var
remaining = element[0].scrollHeight - (element[0].clientHeight + element[0].scrollTop);
//if we have reached the threshold and we scroll down
if (remaining < lengthThreshold && (remaining - lastRemaining) < 0) {
//if there is already a timer running which has no expired yet we have to cancel it and restart the timer
if (promise !== null) {
timeout.cancel(promise);
}
promise = timeout(function() {
handler();
promise = null;
}, timeThreshold);
}
lastRemaining = remaining;
});
}
};
}
]);
<ul class="inbox-list" infinite-scroll="loadData()">
<li class="clearfix" ng-repeat="event in events">{{event}}</li>
</ul>
I Made some changes the more important is the use of ng-transclude and the creation of a new scope for the directive to pass the method and the parameters. You can have a look at the jsbind. Of course the data are hard coded so i could fake the behaviour.
<ul class="inbox-list" my-infinite-scroll composite-method="loadData()">
I created a countdown clock as part of a larger project. Here is the code for the service
'use strict';
angular.module('myApp')
.service('Countdownclock', function Countdownclock() {
var secondsRemaining = 0;
var timerProcess;
return {
//initialize the clock
startClock: function(minutes) {
secondsRemaining = minutes * 60;
timerProcess = setInterval(this.timer, 1000);
},
//timer function
timer: function() {
secondsRemaining -= 1;
if (secondsRemaining <= 0) {
clearInterval(timerProcess);
}
},
//get time
getTime: function() {
return secondsRemaining;
},
//add time
addTime: function(seconds) {
secondsRemaining += seconds;
},
//stop clock
stopClock: function() {
secondsRemaining = 0;
clearInterval(timerProcess);
}
};
});
Then I call it to a from a controller which is also linked to a view
'use strict';
angular.module('myApp')
.controller('MainCtrl', function($scope, Countdownclock) {
Countdownclock.startClock(1);
$scope.seconds = Countdownclock.getTime();
$scope.$watch(Countdownclock.getTime(), function(seconds) {
$scope.seconds = Countdownclock.getTime();
});
});
For some reason I can't figure out how to bind secondsRemaining to $scope.seconds. I've been trying to figure this thing out for about an hour. I'm not exactly a wiz at functional programing so I have a feeling I'm just thinking about it wrong.
Inject $interval into your service and replace setInterval with it:
timerProcess = $interval(this.timer, 1000);
If you want to use a watcher you can register it like this:
$scope.$watch(function () { return Countdownclock.getTime(); }, function (newValue, oldValue) {
// Might be identical when called due to initialization - Good to know for some cases
if (newValue !== oldValue) {
$scope.seconds = newValue;
}
});
Demo: http://plnkr.co/edit/usUoOtWMwoDRht27joOA?p=preview
You can use a function instead:
$scope.seconds = function() { return Countdownclock.getTime() };
Then remove the
$scope.$watch(Countdownclock.getTime(), function(seconds) {
$scope.seconds = Countdownclock.getTime();
});
You can then use it in your template like this:
<div>{{seconds()}}</div>
But first, like Spock said, you have to use $interval instead of setInterval.