I have a controller in which a value gets randomly generated
app.controller('detailReadingCtrl',function(){
var value = 0;
$scope.dispValue = 0;
setInterval(function(){
value = Math.floor(Math.random()*1000);
$scope.dispValue = value;
}
});
and my html is
<div>{{dispValue}}</div>
The Value on the html is not getting updated with the changed value. The dispvalue is changing in the controller but it is not updating in the html. I want to see the value change for every second on the screen without the need of refresh.
I tried using $scope.$watch and also $scope.$broadcast both seem to not work. Please let me know if you have any ideas about this.
setInterval doesn't trigger a $digest cycle, instead, use the $interval module:
app.controller('detailReadingCtrl',function($scope, $interval){
var value = 0;
$scope.dispValue = 0;
$interval(function(){
value = Math.floor(Math.random()*1000);
$scope.dispValue = value;
});
});
And you had other errors in the code ($scope wasn't being injected, missing ) at the end of the interval)
Related
I'm quite new to Angular and am trying to understand how everything works. I've been poking around and couldn't find any information on how to do this. So, I've got a service that defines
this.totalCount = 0;
In my controller, my get request retrieves some emails and then executes a function called addMessage for each message it retrieves. The addMessage function is in my service.
The function in my service looks like this:
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
}
Basically, I am trying to increment this.totalCount each time this function is executed so that it will update and then can be displayed in the view. I have it displaying in the view currently, however its number always remains 0.
I've tried the following:
1.
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
this.totalCount++;
}
2.
var count = this.totalcount
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
count++; //and then attempted to display this value in the view but with no luck
}
Any tips would be greatly appreciated.
try this:
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
}
I assume that you're binding the var this way in your controller and your view
Service :
this.totalCount = 0;
this.totalCount++;
Controller :
$scope.totalCount = service.totalCount;
view :
{{totalCount}}
And if you're actually doing it like this, you should face this kind of trouble.
The main problem is that totalCount is a primitive var and doing this.totalCount++ will break the reference. If you want to keep some var you should bind it as a sub-object.
This way :
Service :
this.utils = {};
this.utils.totalCount = 0;
this.utils.totalCount++;
Controller :
//This is the most important part. You bind an object. Then even if you loose the totalCount reference, your object will keep its own reference.
$scope.myServiceUtils = service.utils;
View :
{{myServiceUtils.totalCount}}
Actually in service (it's a matter of taste) i prefer a lot to use the object syntax instead of this (as "this" can be confusing)
This way :
var service = {};
service.utils.totalCount = 0;
service.addItem = function(){
...
}
return service;
Hope that was your issue.
You pass argument to another function which has different scope than your service. It is trick with assigning current object to variable, which is visible from function.
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
that.totalCount++;
}
Should work.
So you assign that variable with current object, which is visible in inner function scope.
In a function addMessage body, this refers to function scope which is new, and there is no compiler error, but messagesList is a null object and totalCount is incremented, but after program leave function, it's not visible in service, because it is in a function scope which isn't assigned to any variable.
To update service variable as it changes in your controller, use $watch.
$scope.$watch(function() {
return messagesService.totalCount;
}, function(new,old){
$scope.totalmessagecount = messagesService.totalCount;
});
First parameter of $watch if function which return observed for change element. Another is standard function to perform operation after update.
Asking for help with Angular.
Somewhy, cannot refresh property (timerValue) when its value is changed. It does render it once.
Here's html div:
<div>{{ game.timerValue }}</div>
The js:
// Game status
$scope.game = {
"started" : false,
"timerValue" : 60,
"score" : 0,
"question" : "? ? ?",
"message" : "If all options are set up, then you may start!",
"wrong" : ""
};
// Handle Start Button click
$scope.startGame = function () {
if($scope.game.timer) clearTimeout($scope.game.timer);
$scope.game.score = 0;
$scope.game.wrong = "";
$scope.game.message = "The game started!";
$scope.game.timer = setInterval(function() {
$scope.game.timerValue -= 1;
if( $scope.game.timerValue <= 0)
{
$scope.game.message = "Defeat! Time is out! Your score is " + $scope.game.score;
clearTimeout($scope.game.timer);
}
},1000);
};
Running out of ideas, thanks for any help.
Update: The property is changed, the timer is working. It is not refreshing.
The reason your UI is not updated is because your game timer logic runs outside the regular Angular digest cycle. There's a nice article explaining it: $watch How the $apply Runs a $digest.
Instead of using setInterval, it is recommended to use Angular's $interval service. It is a wrapper for window.setInterval and releases you from the duty of having to manually call $scope.$apply or "tell Angular to update the UI".
Additional benefits of using $interval:
It wraps your callback for you automatically in a try/catch block and let's you handle errors in the $exceptionHandler service.
It returns a promise and thus tends to interoperate better with other promise-based code than the traditional callback approach. When your callback returns, the value returned is used to resolved the promise.
An alternative solution would be to explicitly call $scope.$apply() inside setInterval to notify Angular that "model data has changed, update the UI".
you can do a $scope.$apply() at the end of each interval to get what you want to achieve. just be wary of confilicts if you try to do a $scope.$apply() any where inside this function (if you were to extend it) or outside, if you were to extend the function that calls this.
You could also do what #Discosultan suggested and use $interval, which should automatically apply changes to your view from the scope at the end of each interval and will not create conflicts if you use a $scope.$apply() elsewhere in your code. By using $interval it will become part of your digest cycle, and you want to make sure not to put to much computational heavy code inside your digest loop otherwise it could slow down your entire app, as explained below in the comments by #AlvinThompson
setInterval does its work in a separate thread (sort of), so Angular cannot detect any changes to properties it makes. You have to wrap any functions that modifies properties with $scope.$apply(function () {... so that Angular detects them and pushes those changes to the UI.
$scope.$apply();
Working JS Bin
$scope.game.timer = setInterval(function() {
$scope.game.timerValue -= 1;
if( $scope.game.timerValue <= 0)
{
$scope.game.message = "Defeat! Time is out! Your score is " + $scope.game.score;
clearTimeout($scope.game.timer);
}
$scope.$apply();
},1000);
You are refreshing with a function that is outside Angular (setInterval). To tell angular to apply the change in your view, you have two solutions :
using $scope.$apply() :
$scope.startGame = function () {
if($scope.game.timer) clearTimeout($scope.game.timer);
$scope.game.score = 0;
$scope.game.wrong = "";
$scope.game.message = "The game started!";
$scope.game.timer = setInterval(function() {
$scope.game.timerValue -= 1;
$scope.$apply();
if( $scope.game.timerValue <= 0)
{
$scope.game.message = "Defeat! Time is out! Your score is " + $scope.game.score;
clearTimeout($scope.game.timer);
}
},1000);
};
or using $timeout :
$scope.startGame = function () {
if($scope.game.timer) $timeout.cancel($scope.game.timer);
$scope.game.score = 0;
$scope.game.wrong = "";
$scope.game.message = "The game started!";
$scope.game.timer = $timeout(function() {
$scope.game.timerValue -= 1;
if( $scope.game.timerValue <= 0)
{
$scope.game.message = "Defeat! Time is out! Your score is " + $scope.game.score;
$timeout.cancel($scope.game.timer);
}
},1000);
};
Without forgetting to inject ̀$timeout in your controller dependencies.
I'm using angular-timer: http://siddii.github.io/angular-timer/
My goal is to create a timer for an app that keeps reference to a variable somewhere else. That way instead of having a timer that just restarts on page load I will have a timer that consistently counts down regardless of what the user does. Most examples with angular-timer have you enter a countdown number. Is there any way to pass in a variable like so:
var timeRemaining = 1000;
<h1 class="timer"><timer countdown=timeRemaining max-time-unit="'minute'" interval="1000">{{mminutes}} minute{{minutesS}}, {{sseconds}} second{{secondsS}}</timer></h1>
Instead of being forced to write the countdown like this:
countdown="1000"
I've already tried passing in the variable via the toString() method as well. Thanks.
It looks like you cannot do what you are trying to without editing the directive itself.
Alternatively, you could use the timer from this question on your scope, just modify it to count down: https://stackoverflow.com/a/12050481/4322479
Counting down, from the question's comments: http://jsfiddle.net/dpeaep/LQGE2/1/
function AlbumCtrl($scope,$timeout) {
$scope.counter = 5;
$scope.onTimeout = function(){
$scope.counter--;
if ($scope.counter > 0) {
mytimeout = $timeout($scope.onTimeout,1000);
}
else {
alert("Time is up!");
}
}
var mytimeout = $timeout($scope.onTimeout,1000);
$scope.reset= function(){
$scope.counter = 5;
mytimeout = $timeout($scope.onTimeout,1000);
}
}
No need to edit directive, you could also use ng-if on your timer element to check for your startTime variable.
<timer ng-if="yourCountdownVaariable>0" countdown="yourCountdownVaariable"
max-time-unit="'hour'" interval="60000">
{{hhours}} hour{{hoursS}}, {{mminutes}} minute{{minutesS}}
</timer>
This way, the directive will only be initialised when you have your date, and it will work. Original issue below:
https://github.com/siddii/angular-timer/issues/36
I have this...
<script> var num = 22;</script>
Then inside of the controller block...
<span>{{somenumber}}</span>
In the controller...
$scope.somenumber = num;
This all works as expected.
How would I go about having it all update if the value of the num variable changes? So, I'd have some code (from socket.io or AJAX) change num to 65. Right now, it still says 22.
I'd take a look at this
num is a primitive type (Number). So When you're assigning it to the $scope you're copying it. What you need to do is reference it instead. I'd fix it the following way.
<script>var value = {num: 22} </script>
$scope.value = value;
<span> {{value.num}} </span>
If your ajax call is not through $http.(outside angular - wherever you set value.num) you'll need to invoke a digest cycle. The easiest way to do that is in an angular service like $timeout.
Think of the scope as
$scopeHAS model instead of $scopeAS model
You could use $watch followed by $apply:
Controller
$scope.somenumber = num;
$scope.$watch(function() {
return num;
}, function(newValue, oldValue) {
$scope.somenumber = newValue;
});
// fake external change to the 'num' variable
setTimeout(function() {
num = 33;
$scope.$apply();
}, 3000);
Here's a working example: http://plnkr.co/edit/rL20lyI1SgS6keFbckJp?p=preview
If your external change is happening outside the scope of a single controller, I would use $rootScope inside a run callback:
angular.module('exampleApp', []).run(function($rootScope) {
// same as above, just with $rootScope
});
I am trying to add two numbers but for some reason I am not getting NaN.
Following is the sample code
function Slider(container, nav, pagination){
this.articleWidth = this.div.width() + 20;
this.divWidth = 960;
this.articleMargin = 0;
this.pageMargin = this.divWidth + this.articleMargin
}
Slider.prototype.articleTransition = function(pageNum){
var currArticle = pageNum -1;
this.articleMargin = currArticle * this.articleWidth;
this.container.animate({'margin-left': -this.articleMargin});
}
Here everything works as expected. But this.pageMargin is always 0 even though this.articleMargin's value is changing in the articleTransition function. And when I console log this.pageMargin is says NaN. I am trying to change value of this.articleMargin's value, everytime it is being invoked in the function.
Here is how I am invoking the function in my HTML.
var slider = new Slider($('div#contentSleeve'), $('a.anav'), $('ul#scroller li'));
slider.pagination.live('click', function(){
slider.articleTransition($(this).data('num'));
});
I guess that's because you are calling in anonymous function scope. Try like this:
slider.articleTransition.call(slider, $(this).data('num'));
I did fix this. All I had to do was to create a global variable that will store the value of both pageMargin and ArticleMargin.