How to update html element in ng-repeat collection every second automatically - angularjs

In my controller I have a function that receives data from API every 2 seconds($interval). This data is rendered and displayed to user. When I get positive numbers from my API I want to set background color in HTML to green for 1 second and return it to original color. If it is negative, set background color to red for 1 second, and so on...
controller.js
function checkForUpdatedIndices(){
dataService.getIndices().then(function(res){
$scope.recentIndeces = res.data;
});}
var indicesTimer = setInterval(checkForUpdatedIndices,2000);
checkForUpdatedIndices();
My HTML:
<ul id="ctr_indices">
<li class="cl_indeces" ng-repeat="i in recentIndeces track by $index">
<span class="itemname">{{i.itemName}}</span>
<span class="itemlastvalue">{{i.itemLastValue}}</span>
<span class="itemchange">{{i.itemChange}}</span>
<span class="itempercentage">{{i.itemPercentageChange}}</span>
</li>
</ul>
When i.itemLastValue contains "+" I want to see it green for 1 second and after that change it back to original color.
Thanks in advance

you can do this using ng-style directive. set this style like this
ng-style="{'background-color' : i.color}"
and call a function inside ng-init and pass the item as a parameter
<span class="itemlastvalue" ng-style="{'background-color' : i.color}" ng-init="setColor(i)">{{i.itemLastValue}}</span>
In the function assign the color according to the condition and use timeout function to reverse it to the original value
$scope.setColor = function(i){
if( i.itemLastValue == "+"){
i.color = 'green'
}
else if( i.itemLastValue == "-"){
i.color = 'red'
}
$timeout(function(){
i.color = "white" // what ever the original value
},1000)
}
UPDATED
the second scenario is removing the ng-init function and call the function inside checkForUpdatedIndices
function checkForUpdatedIndices(){
dataService.getIndices().then(function(res){
$scope.recentIndeces = res.data;
setColor()
});
}
function setColor(){
var backUp = angular.copy($scope.recentIndeces);
for(var i=0; i<= $scope.recentIndeces.length-1; i++){
if( $scope.recentIndeces[i].itemLastValue == "+"){
$scope.recentIndeces[i].color = 'green'
}
else if( $scope.recentIndeces[i].itemLastValue == "-"){
$scope.recentIndeces[i].color = 'red'
}
}
$timeout(function(){
$scope.recentIndeces = angular.copy(backUp);
},1000)
}

Related

Retain scroll position after new items added to angular collection ng-repeat

We're creating chat in our project and get issue with messages loading when user scrolls top. We need create something like infinite scroll but when user scrolls top. The main issue we get is - when we get new X messages and unshift it to collection scroll position always gets top. How we can retain scroll position after each new element is added to collection ?
Our code is simple ng-repeat in html and ajax call in controller.
Html structure:
<div class="messages-view-bg messages-list-container has-footer" ng-class="{'searching' : showSearchBar}" id="userMessagesView" style="height: {{deviceHeight-75}}px">
<div class="row" ng-if="conversation.description !== undefined" style="text-align: center; color: grey">
<p style="width: 100%">{{conversation.description}}</p>
</div>
<div class="conversation-bubble" in-view="$inview && $index == 1 && loadmore()" ng-repeat="message in messages track by $index" id="msg-{{message.id}}">
</div>
{{message.content}}
</div>
method what loads new messages:
var messageLoader = function(callback){
$scope.loaderIndicator = true;
Conversation.loadMessages({}).$promise.then(function(data){
$scope.loaderIndicator = false;
if($scope.messages && $scope.messages.length > 0) {
data.messages.forEach(function (item, index){
$scope.messages.unshift(item);
});
read();
} else {
$scope.messages = data.messages;
read();
}
$scope.$broadcast('scroll.refreshComplete');
isMore = data.messages.length == 30;
if(firstLoad) {
isMore = data.messages.length == 30;
} else {
isMore = data.messages.length == LOAD_MSG_COUNT;
}
$scope.skipCount += LOAD_MSG_COUNT;
if(firstLoad){
scrollToBottom();
}
});
}

scope variable not updating with ng-change - angularjs

Seems like a simple problem though but finding it hard to fix.
There is a pagination component, that has a button & a dropdown. User can go to a page by either clicking the button or selecting that page number in dropdown.
The problem is, when I select a value in the dropdown, nothing happens. Because the scope variable doesnt change from the previous one.
aspx:
<div data-ng-app="app" data-ng-controller="ReportsCtrl">
<div id="paging-top">
<div>
<ul>
<li>
<select data-ng-model="SelectedPage" data-ng-change="ShowSelectedPage();"
data-ng-options="num for num in PageNumbers track by num">
</select>
</li>
<li data-ng-click="ShowNextPage();">Next</li>
</ul>
</div>
</div>
app.js
var app = angular.module("app", ["ngRoute"]);
ReportsCtrl.js
app.controller("ReportsCtrl", ["$scope","ReportsFactory",function ($scope,ReportsFactory) {
init();
var init = function () {
$scope.ShowReport(1);
}
$scope.ShowReport = function (pageNumber) {
GetUserResponsesReport(pageNumber);
}
function GetUserResponsesReport(pageNumber) {
$scope.UserResponsesReport = [];
var promise = ReportsFactory.GetReport();
promise.then(function (success) {
if (success.data != null && success.data != '') {
$scope.UserResponsesReport = success.data;
BindPageNumbers(50, pageNumber);
}
});
}
function BindPageNumbers(totalRows, selectedPage) {
$scope.PageNumbers = [];
for (var i = 1; i <= 5 ; i++) {
$scope.PageNumbers.push(i);
}
$scope.SelectedPage = selectedPage;
}
$scope.ShowSelectedPage = function () {
alert($scope.SelectedPage);
$scope.ShowReport($scope.SelectedPage);
}
$scope.ShowNextPage = function () {
$scope.SelectedPage = $scope.SelectedPage + 1;
$scope.ShowReport($scope.SelectedPage);
}
}]);
Say, the selected value in dropdown is 1. When I select 2 in the dropdown, the alert shows1. When Next is clicked, the dropdown selection changes to 2 as expected. Now, when I select 1 in the dropdown, the alert shows 2.
Tried to make a fiddle, but do not know how to do with a promise - http://jsfiddle.net/bpq5wxex/2/
With your OP SelectedPage is just primitive variable.
With every angular directive new scope is get created.
So,SelectedPage is not update outside the ng-repeat scope after drop-down is changed i.e. in parent scope which is your controller.
In order to do this,use Object variable instead of primitive data types as it update the value by reference having same memory location.
Try to define SelectedPage object in controller in this way.
$scope.objSelectedPage = {SelectedPage:''};
in HTML
<select data-ng-model="objSelectedPage.SelectedPage" data-ng-change="ShowSelectedPage();"
In ShowSelectedPage
$scope.ShowSelectedPage = function () {
console.log($scope.objSelectedPage.SelectedPage);
$scope.ShowReport($scope.objSelectedPage.SelectedPage);
}

How to show element once in ng-repeat

I need to loop through a list order by price and as soon as the price is not there then I show a message with unavailable but I don't want to show it for each empty element. I'm using angular 1.2
<div ng-repeat="item in list | orderBy: 'cost'">
<div ng-if="cost == 0 and not already shown">Sorry the following are unavailable</div>
<div>...my item here...</div>
<div>
You can conditionally display two spans - one if it's 0 (your 'not available' message) and another for anything else.
<ul>
<li ng-repeat="d in newData track by $index">
<span ng-show="d > 0">{{d}}</span>
<span ng-show="d === 0">Not Available</span>
</li>
</ul>
The data can be passed through a function to pull all the 0 after the first one:
$scope.data = [1,2,3,0,1,0,0,1,0,2]
$scope.pullDupes = function(array) {
var newArray = [];
var zero;
for(var i = 0; i < array.length; i++) {
if (array[i] !== 0) {
newArray.push(array[i])
}
if (array[i] === 0 && !zero) {
zero = true;
newArray.push(array[i])
}
}
return newArray;
}
$scope.newData = $scope.pullDupes($scope.data);
Plunker
You can show only the first message see here :
<div ng-repeat="item in list | orderBy: 'cost'">
<div style="color:red" ng-show="item.cost == 0 && $first">Message Goes Here</div>
<hr>
<div>{{item.name}} - Price : {{item.cost}}</div>
</div>
and here is a plunker for it :
http://plnkr.co/edit/RwZPZp9rFIChWxqF71O7?p=preview
also the ng-if you are using it wrong you need to do it like this item.cost for the next time
Cheers !
Here is the best way I could find to get it done.
Markup
<div class="sold-out-message" ng-if="displaySoldOutMessage(item)">Sorry, sold out</div>
Controller
$scope.firstSoldOutItemId = false;
$scope.displaySoldOutMessage = function(item) {
if ( item.cost ) return false;
$scope.firstSoldOutItemId = $scope.firstSoldOutItemId || item.id;
return item.id == $scope.firstSoldOutItemId;
};
You can try to use $scope.$whatch with a boolean variable like this:
<div ng-model="actualItem" ng-repeat="item in list | orderBy: 'cost'">
<div ng-if="cost == 0 && oneMessage == true">Sorry the following are unavailable</div>
<div>...my item here...</div>
<div>
</div>
And in your controller you look at actualItem :
$scope.oneMessage = false;
var cpt = 0; // if 1 so you stop to send message
$scope.$watch('actualItem',function(value){
if(value.cost == 0 && $scope.oneMessage == false && cpt < 1)
// i don't know what is your cost but value is your actual item
{
$scope.oneMessage = true;
cpt++;
}
else if($scope.oneMessage == true)
{
$scope.oneMessage == false;
}
});
I am not sure about this but you can try it. It's certainly not the best way.

count value in a array into ng-repeat

I have this data : http://www.monde-du-rat.fr/API/moulinette/radio/posts.json , from cakephp app, it's song by song, with attached votes
I use it as a service into a angularjs app, and i displayed it like this in html :
<div ng-repeat="song in songs | orderBy:'Radio.idSong' | notesong:'Radiovote'" class="list-group-item" id="{{song.Radio.idSong}}" ng-class="{ 'active' : songPlayed_name == song.Radio.name }" ng-if="songs">
<span>{{song.Radio.idSong}} - {{song.Radio.title}}</span><br />
<span>{{note}}%</span>
</div>
So, i want to count each attached vote, and define with values 'good' or 'bad', the % of likes
I try to made this filter :
/* notesong */
app.filter('notesong', function() {
return function(input) {
// counter init
var countGood = 0;
// if there is no votes, so note is zero
if (!angular.isArray(input)) {
var note = 0;
} else {
// loop for each vote (from Radiovote array, each value)
angular.forEach(input, function () {
if (input.value == 'good') {
countGood = countGood + 1;
}
});
var note = (countGood * input.length) / 100;
}
// final return
return note;
};
});
It's not working apparently (no errors, and no data displayed), so, what is the correct way ?
You are applying the filter in the wrong place. Instead of using it on the ng-repeat you should use it on the property you want to bind, like this:
<div ng-repeat="song in songs | orderBy:'Radio.idSong'" class="list-group-item" id="{{song.Radio.idSong}}" ng-class="{ 'active' : songPlayed_name == song.Radio.name }" ng-if="songs">
<span>{{song.Radio.idSong}} - {{song.Radio.title}}</span><br />
<span>{{song.Radiovote | notesong}}%</span>
</div>
There's also a problem with the way you are looping the votes in your filter. Update the following lines:
// loop for each vote (from Radiovote array, each value)
angular.forEach(input, function (item) {
if (item.value == 'good') {
countGood = countGood + 1;
}
});

$index inside ng-repeat with ng-if

I Have an array of items like this which contains a list of animals and a list of fruits in a random order.
$scope.items = [{name:'mango',type:'fruit'},{name:'cat',type:'animal'},{name:'dog',type:'animal'},{name:'monkey',type:'animal'},{name:'orange',type:'fruit'},{name:'banana',type:'fruit'},...]
Then I Have a array of colors like
$scope.colorSeries = ['#3366cc', '#dc3912', '#ff9900',...];
$scope.setBGColor = function (index) {
return { background: $scope.colorSeries[index] }
}
I am using the items array to render the fruits only in a div with background color selected from the colorSeries based on the index like colorSeries[0] which will give me #3366cc
<div data-ng-repeat="item in items " ng-if="item.type =='fruit'">
<label ng-style="setBGColor($index)">{{item.name}}</label>
</div>
Things working fine if the length of the items array is less than length of colorSeries array.The problem arises if the length of colorSeries array is less than the items array.e.g if i have a color series with 3 colors then for this items array the last item i.e orange will need a color indexed as colorSeries[4] which is undefined where as I have rendered only three items. So, is it possible to get the index like 0,1,2 i.e the index of elements rendered with ng-if.
Instead of using ng-if, I would use a filter. then, the $index will be always correspond to the index in the result list after applying the filter
<div data-ng-repeat="item in items|filterFruit">
<label ng-style="setBGColor($index)">{{item.name}}</label>
</div>
angular.module('app.filters', []).filter('filterFruit', [function () {
return function (fruits) {
var i;
var tempfruits = [];
var thefruit;
if (angular.isDefined(fruits) &&
fruits.length > 0) {
for(thefruit = fruits[i=0]; i<fruits.length; thefruit=fruits[++i]) {
if(thefruit.type =='fruit')
tempfruits.push(thefruit);
}
}
return tempfruits;
};
}]);
Try this..
this.itemList = [{
name:'apple'
}, {
name: 'fruit'
}];
this.colorlist = [{ color: 'red' }, { color: 'orange' }, { color: 'blue' }];
<div data-ng-repeat="item in itemList " ng-if="item.name=='fruit'">
<label ng-style="colorlist [$index]">{{item.name}}</label>
</div>
If I were you, I would embed the colors inside the $scope.items objects, since you always use them coupled with a fruit.
Anyway, to address your specific code configuration, I would add a counter in my controller and use it to loop through the colors.
Something like this:
app.controller('myCtrl', function ($scope) {
$scope.colorSeries = ['#3366cc', '#dc3912', '#ff9900',...];
var colorCounter = $scope.colorSeries.length;
var colorIdx = -1;
$scope.setBGColor = function () {
// get back to the first color if you finished the loop
colorIdx = colorCounter? 0: colorIdx+1
return { background: $scope.colorSeries[colorIdx] }
}
})
And then in your view (note that there is no $index)
<div data-ng-repeat="item in items " ng-if="item.type =='fruit'">
<label ng-style="setBGColor()">{{item.name}}</label>
</div>

Resources