AngularJs Counter to count up to a specific target number - javascript

I am trying to create a counter using Angularjs which should count up to a number which is already present in that division. Here is my html snippet.
<div class="circle-home">
<span class="circle-home-score " id="counterofreviews" data-count="{{noReviews}}">{{noReviews}}</span> REVIEWS
</div>
Now when I am trying to get the value inside the span I get it as {{noReviews}} instead of its value.
Here is my AngularJs code.
var demoApp = angular.module(['demoApp','ngRoute','ui.bootstrap']);
demoApp.controller('SearchController',function ($scope, $http, $facebook, $interval){
$scope.noReviews=100;
$scope.childOnLoad = function() {
$scope.uppercount=$("#counterofreviews").text();
$scope.no_Reviews=0;
console.log($scope.uppercount);
var stop;
stop = $interval(function() {
if ($scope.uppercount >$scope.no_Reviews) {
$scope.noReviews=$scope.no_Reviews;
$scope.no_Reviews++;
console.log('Inside if statement');
} else {
$scope.stopFight();
}
}, 100);
};
$scope.stopFight = function() {
if (angular.isDefined(stop)) {
$interval.cancel(stop);
stop = undefined;
}
};
$scope.childOnLoad();
};
Output of console.log($scope.uppercount) is {{noReviews}}. I am unable to figure out a proper way to do it. Please suggest the correction or any other better method for the same perpose.

Not sure why do you use jQuery to get the #counterofreviews value. Is the value there because it's added from a server side script?
As mentioned in the comments, your code is probably not working because jQuery.text() is returning a string. Using parseInt(text) could work.
Please have a look at the demo below and here at jsfiddle.
It's more Angular and should help you getting started with your counter.
var demoApp = angular.module('demoApp', []); //'ngRoute','ui.bootstrap']);
demoApp.controller('SearchController', function ($scope, $http, $interval) { //$facebook,
$scope.noReviews = 100;
//$scope.childOnLoad = function () {
this.upperCount = 10; //$("#counterofreviews").text();
console.log(this.upperCount);
var stop;
this.startCounter = function () { // needed for re-run on change
//console.log(stop, this);
this.no_Reviews = 0;
if ( angular.isUndefined(stop) )
stop = $interval(checkCount.bind(this), 100);
};
this.startCounter();
//};
function checkCount() {
if (this.upperCount >= this.no_Reviews) {
this.noReviews = this.no_Reviews;
this.no_Reviews++;
//console.log('Inside if statement');
} else {
stopFight();
}
}
function stopFight() {
if (angular.isDefined(stop)) {
$interval.cancel(stop);
stop = undefined;
}
};
//$scope.childOnLoad();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" class="circle-home" ng-controller="SearchController as ctrl">Review max.:
<input ng-model="ctrl.upperCount" ng-change="ctrl.startCounter()"/> <span class="circle-home-score " id="counterofreviews" data-count="{{ctrl.upperCount}}">{{ctrl.noReviews}}</span> REVIEWS</div>

Related

ng-bind-html not working

I'm trying to insert HTML into my div (bottom of code). I've dealt with an issue like this before so I added a filter. However, when the div is made visible through a toggle function the HTML doesn't display from the service. I have verified that the service is returning the proper HTML code.
The div is unhidden but no html is displayed.
Angular Code:
var myApp = angular.module('myApp', []);
angular.module('myApp').filter('unsafe', function ($sce) {
return function (val) {
if ((typeof val == 'string' || val instanceof String)) {
return $sce.trustAsHtml(val);
}
};
});
myApp.controller('myAppController', function ($scope, $http) {
...
SERVICE CODE
...
$scope.toggleHTMLResults();
$scope.HTMLjson = obj[0].HTML;
HTML Code:
<div id="returnedHTML" ng-bind-html="HTMLjson | unsafe " ng-hide="HTMLResults">NOT HIDDEN</div>
I'm not sure why this isn't working.
Here is my Plunker
There were multiple things wrong with your example.
Main Javascript file declared twice, first in header and second before close on body tag
You call a function as HTMLAPI() instead of $scope.HTMLAPI()
Your $scope.HTMLAPI() function was also being called before it was initialised
Fixed controller code:
app.controller('myAppCTRL', ['$scope', '$http', function ($scope, $http) {
var API = this;
$scope.HTMLInput = true;
$scope.HTMLResults = true;
$scope.toggleHTMLInput = function () {
$scope.HTMLInput = $scope.HTMLInput === false ? true : false;
}
$scope.toggleHTMLResults = function () {
$scope.HTMLResults = $scope.HTMLResults === false ? true : false;
}
$scope.HTMLAPI = function (HTML) {
var newJSON = ["[{\"ConditionId\":1111,\"ConditionDescription\":\"<i>DATA GOES HERE</i>\",\"ErrorId\":0,\"DisplayId\":0,\"DisplayName\":\"\",\"ErrorValue\":\"\"}]"];
var obj = JSON.parse(newJSON);
$scope.HTMLjson = obj[0].ConditionDescription;
$scope.toggleHTMLResults();
console.log($scope.HTMLjson);
}
$scope.HTMLAPI();
}]);
Working Example

Angular auto trigger specific directive in ng-repeat

I have an interesting situation.
I have a directive with isolate scope that generate list of numbers and the user can choose numbers like in lottery.
The problem i have is that i required minimum of 1 line, if the user pick only one line so when he click play i want to auto trigger the next directive in the ng-repeat to pick for him numbers, I made this plunker so you guys can understand better and help me.
http://plnkr.co/edit/vWGmSEpinf7wxRUnqyWq?p=preview
<div ng-repeat="line in [0,1,2,3]">
<div line line-config="lineConfig">
</div>
</div>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.lineConfig = {
guessRange: 10
}
$scope.lines = [];
$scope.$on('lineAdded', function(event, line) {
$scope.lines.push(line);
});
$scope.play = function() {
/// here i want to check if $scope.lines.length
//is less then one if yes then auto trigger the next
//line directive to auto do quick pick and continue
}
})
.directive('line', function() {
return {
restrict: 'A',
templateUrl: 'line.html',
scope: {
lineConfig: '='
},
link: function($scope, elem, attr) {
var guessRange = $scope.lineConfig.guessRange;
$scope.cells = [];
$scope.line = {
nums: []
};
$scope.$watch('line', function(lotLine) {
var finaLine = {
line: $scope.line
}
if ($scope.line.nums.length > 4) {
$scope.$emit('lineAdded', finaLine);
}
}, true);
_(_.range(1, guessRange + 1)).forEach(function(num) {
$scope.cells.push({
num: num,
isSelected: false
});
});
$scope.userPickNum = function(cell) {
if (cell.isSelected) {
cell.isSelected = false;
_.pull($scope.lotLine.nums, cell.num);
} else {
cell.isSelected = true;
$scope.lotLine.nums.push(cell.num);
}
};
$scope.quickPick = function() {
$scope.clearLot();
$scope.line.nums = _.sample(_.range(1, guessRange + 1), 5);
_($scope.line.nums).forEach(function(num) {
num = _.find($scope.cells, {
num: num
});
num.isSelected = true;
});
}
$scope.clearLot = function() {
_($scope.cells).forEach(function(num) {
num.isSelected = false;
});
$scope.line.nums = [];
}
}
}
})
You could pass the $index (exists automatically in the ng-repeat scope) - variable into the directive and cause it to broadcast an event unique for ($index + 1) which is the $index for the next instance.
The event could be broadcasted from the $rootScope or a closer scope that's above the repeat.
Then you could capture the event in there.
Probably not the best way to do it.
I can try to elaborate if anything is unclear.
EDIT
So I played around alittle and came up with this:
http://plnkr.co/edit/ChRCyF7yQcN580umVfX1?p=preview
Rather
Rather than using events or services I went with using a directive controller to act as the parent over all the line directives inside it:
.directive('lineHandler', function () {
return {
controller: function () {
this.lines = [];
}
}
})
Then requiring 'lineHandler' controller inside the 'line' directive - the controller being a singleton (same instance injected into all the line directives) - you can then setup that controller to handle communication between your directives.
I commented most of my code in the updated plnkr and setup an example of what I think you requested when clicking in one list - affecting the one beneath.
I hope this helps and if anything is unclear I will try to elaborate.

Trying to bind variables that are changed in event

I have an AngularJS page which contains the following buttons:
<button class="ui button" ng-click="startTimer()" ng-show="!timerRunning">START</button>
<button class="ui button" ng-click="stopTimer()" ng-show="timerRunning">STOP</button>
I also have this piece of code defined in my controller:
$scope.timerRunning = false;
$scope.timerDone = false;
$scope.startTimer = function () {
$scope.$broadcast('timer-start');
$scope.timerRunning = true;
$scope.timerDone = false;
};
$scope.stopTimer = function () {
$scope.$broadcast('timer-stop');
$scope.timerRunning = false;
$scope.timerDone = true;
};
$scope.$on('timer-stopped', function (event, data) {
console.log('Timer Stopped - data = ', data);
});
$scope.$on('timer-tick', function (event, args) {
if (args.millis == 0) {
$scope.stopTimer();
}
});
I would expect that when timer hits 0 (it's a countdown timer taken from here) the flag timerDone and timerRunning would be changed and so would the buttons display. But in fact it doesn't happen. I debugged it and saw that I get into the stopTimer() method and that the variables are changed but the buttons stay hidden/shown respectively as they were before the timer hit 0.
I guess I'm missing something with the scope here as I'm pretty new to angular but I just couldn't figure out how to overcome this.
Looks like it was a prototypal inheritance issue like Rob J was right. What I did was to fix the even listener as follows (added $scope.$apply()):
$scope.$on('timer-tick', function (event, args) {
if (args.millis == 0) {
$scope.stopTimer();
$scope.$apply();
}
});

How to trigger a controller function after an Animation in Angular JS

I have come to a standstill in terms on threading together a sequence of Animations and then a controller action.
What I basically want to do is basically
1. click on a button/div, 2.Trigger an Animation, 3. Once animation is complete run a function in a controller that resets the button/div
I have completed steps 1 & 2 and just need to get the last bit done.
Here is the Button
<button ng-class="{'clicked':clicked, 'correct' : answer.answer == 'correct' }"
ng-click="clicked = true"
ng-repeat='answer in answers'
type="button"
class="btn btn-answers answer-animation">
{{ answer.es }}
</button>
Here is the animation
app.animation('.answer-animation', function(){
return {
beforeAddClass: function(element, className, done){
if (className === 'clicked') {
if( $(element).hasClass('correct') ){
$(element).addClass('animated bounce');
} else {
$(element).addClass('animated wobble');
}
}
else {
done();
}
}
};
});
And here is the last step the controller, I want the trigger the submitAnswer function inside this controller, after the animation has finished. The main bit is submitAnswer
app.controller('Game', function($scope, $http, $location, QA, Rounds ) {
//Reset all QA buckets
QA.reset();
$scope.round = 1;
$scope.playing = true;
QA.setUpGameData();
$scope.answers = QA.answers();
$scope.question = QA.question();
$scope.submitAnswer = function(question, answer){
if($scope.round <= Rounds) {
if(question.en === answer.en){
$scope.round++;
QA.setUpGameData();
$scope.answers = QA.answers();
$scope.question = QA.question();
if($scope.round === Rounds + 1){
$scope.playing = false;
$scope.message = 'Amazing well done!';
$scope.score = ($scope.round-1) * 1000;
}
}
else {
$scope.playing = false;
$scope.message = 'Sorry Wrong Answer :(';
$scope.score = ($scope.round-1) * 1000;
}
}
};
})
I have tried writing the ng-click in the HTML like so
ng-click="clicked = true;submitAnswer(question, answer)"
and then setting a $timeout on the submintAnswer function, but does really get the UX the app deserves.
Again ultimately I want a way to trigger the submitAnswer function in the controller after the animation is completed.
You can get the $scope of an element using,
var $scope = angular.element(element).scope();
Though there are some problems with syncing the scope if this happens.

How to set ng-disabled inside directive

My directive has
link: function ($scope, $elm, $attrs) {
var status = $scope.item.status
if (status) {
var statusName = status.name,
item = $scope.item;
if (statusName === 'USED') {
$attrs.$set('ng-disabled', true); // this doesn't work
} else {
$elm.attr('ng-disabled', false);
}
}
}
So, my question is:
How to apply ng-disabled to element with this directive?
if (statusName === 'USED') {
$attrs.$set('disabled', 'disabled');
} else {
$elm.removeAttr('disabled');
}
Why invoke ng-disable at all? You're already once evaluating the condition yourself, so having ng-disable evaluating it again is redundant.
You would set ng-disabled to a scope variable, ex:
<input ng-disabled="isDisabled" />
And then inside your directive you can set that variable:
$scope.isDisabled = true;
//html
<div ng-app="miniapp" ng-controller="MainCtrl">
<input type="submit" mydir>
</div>
//js
'use strict';
var app = angular.module('miniapp', []);
app.directive('mydir', function ($compile) {
return {
priority:1001, // compiles first
terminal:true, // prevent lower priority directives to compile after it
compile: function(el) {
el.removeAttr('mydir'); // necessary to avoid infinite compile loop
return function(scope){
var status = scope.item.status
if (status === 'USED') {
el.attr('ng-disabled',true);
} else {
el.attr('ng-disabled',false);
}
var fn = $compile(el);
fn(scope);
};
}
};
});
app.controller('MainCtrl', function ($scope) {
$scope.item = {};
$scope.item.status = 'USED';
});
credit to Ilan Frumer

Categories

Resources