Reputation: 1662
As I'm currently trying to make a smart mirror system based on angularJS, I started making a clock component as basic. Having done a bit of angular before, but not using component structure, I decided to give that a shot.
The angularJS component tutorial quickly learned me to not use $scope
, but this
instead, I wrote my component as follows:
angular
.module('smartMirrorFrontend', [])
.component('clock', {
template: '<div class="iface-component" id="component-clock">' +
'<h1>Clock component Angular</h1>' +
'<span id="clock-hours" >{{ $ctrl.hh }}</span>:' +
'<span id="clock-minutes">{{ $ctrl.mm }}</span>:' +
'<span id="clock-seconds">{{ $ctrl.ss }}</span>' +
'</div>',
controller: function ClockController($interval){
this.hh = this.mm = this.ss = null;
this.clock = function (){
const d = new Date();
this.hh = ('0' + d.getHours()).slice(-2);
this.mm = ('0' + d.getMinutes()).slice(-2);
this.ss = ('0' + d.getSeconds()).slice(-2);
};
this.clock();
$interval(this.clock, 1000);
}
});
Now, this all works perfectly fine, besides the fact that neither $interval
nor $timeout
seem to be able to fire my function every second.
Here's the small catch: I have checked out other AngularJS clock questions on stackoverflow, but none implement it in the this
style, and are using $scope
instead. They also just place the values in one span, while I need this clock to be able to stand in vertical mode (so top to bottom) in separate spans (as seen in the template part)
The console in the webbrowser is not showing any problems, the component displays and loads the time once and correctly, meaning the function does fire once as it should. The component is inserted in the html using <clock></clock>
My question being: Why is my interval not working as it should be, and how can I make it work?
Upvotes: 1
Views: 775
Reputation: 4021
At the start of your directive you can assign this to a variable:
var self = this;
This allows you to know that self refers to the directive. This is useful when you are using this inside of other functions.
you need to set a timeout inside of your clock function, so that it keeps calling it's self
self.clock = function (){
var d = new Date();
self.hh = ('0' + d.getHours()).slice(-2);
self.mm = ('0' + d.getMinutes()).slice(-2);
self.ss = ('0' + d.getSeconds()).slice(-2);
this.time = new Date();
$timeout(self.clock,new Date().getTime() % 1000);
};
This timeout is set to call the function on the next second.
Upvotes: 1
Reputation: 22323
The issue here is not with $interval
but with the localized scoping of this
.
this
is a unique identifier in JavaScript, that is scoped to the particular function that calls it. In the code presented here, this
is pointing to the clock()
function, not the ClockController
function when the $interval
is executed.
There are two ways to fix this issue; one simplistic method would be to create an alias to this
so that it can be referenced inside the callback. The other method would be to use .bind()
. I will demonstrate the alias method here:
controller: function ClockController($interval) {
var comp = this;
this.hh = this.mm = this.ss = null;
this.clock = function() {
const d = new Date();
comp.hh = ('0' + d.getHours()).slice(-2);
comp.mm = ('0' + d.getMinutes()).slice(-2);
comp.ss = ('0' + d.getSeconds()).slice(-2);
console.log(comp);
};
this.clock();
$interval(this.clock, 1000);
}
http://plnkr.co/edit/NFmP29re497d5kyJnqNP?p=preview
Upvotes: 2