Never ending loop through array in AngularJS + setTimeout after each iteration - angularjs

How can I achieve a never ending loop in AngularJS?
my try:
item_list = [{'id':1, 'photo':'path/src'}, {'id':2, 'photo':'path/src'}, {'id':3, 'photo':'path/src'}];
item_list.map(function(item) {
setTimeout( function () {
setCoverImage(item.photo);
}, 5000);
)
I'm going to change cover image using setCoverImage() every 5 s using data from item_list.

First you should use AngularJS's $interval. Then simply increment a counter and use it to access the current element's photo property in your controller and use ng-src to reflect that URL in your img tag.
<img ng-src="{{myCtrl.item_list[myCtrl.currentIndex].photo}}">
Be careful that you never assign to the counter a value that would not correspond to an element in your array.
if ((that.currentIndex + 1) >= that.item_list.length)
See full example below
angular.module('appModule', []).controller('MyController', ['$scope', '$interval', function($scope, $interval) {
this.item_list = [{
'id': 1,
'photo': 'https://i.pinimg.com/736x/32/76/a2/3276a2111c65b2131ef834736f47162b--birthday-kitten-birthday-hats.jpg'
}, {
'id': 2,
'photo': 'http://img.playbuzz.com/image/upload/f_auto,fl_lossy,q_auto/cdn/154cb38e-55e3-4294-bffe-6906b6a41a6b/c33bcc8b-40be-49c9-bad1-ee85f8275189.jpg'
}, {
'id': 3,
'photo': 'http://4.bp.blogspot.com/-J4ioK5aRks8/Tx8d9D5K54I/AAAAAAAAABM/iTL4sbsNYmc/w1200-h630-p-k-no-nu/Surprised+and+serious+kitten.jpg'
}];
var that = this;
this.currentIndex = 0;
$interval(function() {
if ((that.currentIndex + 1) >= that.item_list.length) {
that.currentIndex = 0;
} else {
that.currentIndex++;
}
}, 5000);
}])
angular.bootstrap(window.document, ['appModule'], {
strictDi: true
});
<div ng-controller="MyController as myCtrl">
<img ng-src="{{myCtrl.item_list[myCtrl.currentIndex].photo}}">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>

Use the $interval service of AngularJS like this:
$interval( function () {
setCoverImage(item.photo);
}, 5000);

Inject $interval service in your controller/service (whatever) and then you can use something like this:
let currentPhotoIdx = 0;
const maxAvailablePhotoIdx = item_list.length - 1;
$interval(() => {
setCoverImage(item.photo[currentPhotoIdx]);
currentPhotoIdx === maxAvailablePhotoIdx ? currentPhotoIdx = 0 : currentPhotoIdx++;
}, 5000);

Alternative solution to $interval is $timeout:
function setCoverImageLoop(photo) {
$timeout(function () {
setCoverImage(photo);
setCoverImageLoop(photo);
}, 5000);
}
item_list = [{'id':1, 'photo':'path/src'}, {'id':2, 'photo':'path/src'}, {'id':3, 'photo':'path/src'}];
item_list.map(function(item) {
setCoverImageLoop(item.photo);
});
This is probably a bit old-school, and mainly for people who preferred coming from setTimeout.

Related

accessing Json key-value pair for angularjs controller using services

I have been trying to use data from my service for a chart in my angularjs controller.I have made a service in service.js which i am using in my controller.All i get is the Object array,but when i try to access values inside the Object array ,it throws errors for each approach i use .Following is what i am doing
My Service
var demoService= angular.module('demoService',[])
.service('myService',function($http,$q){
var deferred = $q.defer();
$http.get('http://enlytica.com/RSLivee/rest/census').then(function(data)
{
deferred.resolve(data);
});
this.getPlayers=function()
{
return deferred.promise;
}
})
My Controller
angular.module("app.controllers", [])
.controller("gaugeCtrl", ["$scope","config","myService",
function ($scope,config,myService) {
var promise=myService.getPlayers();
promise.then(function(data)
{
$scope.players=data.data;
//console.log($scope.players.Tweets);
($scope.players.Tweets).each(function(index, element) {
console.log(element.FAVOURITE_COUNT);
});
});
return $scope.gaugeHome = {
gaugeData: {
maxValue: 9000,
animationSpeed: 100,
val: 1000
},
gaugeOptions: {
lines: 12,
angle: 0,
lineWidth: 0.47,
pointer: {
length: 0.6,
strokeWidth: 0.03,
color: "#555555"
},
limitMax: "false",
colorStart: config.secondary_color,
colorStop: config.secondary_color,
strokeColor: "#F5F5F5",
generateGradient: !0,
percentColors: [
[0, config.secondary_color],
[1, config.secondary_color]
]
}
}
I have also included the service Module in my app.js :
var app = angular.module("app",["demoService"])
How can i access a particular value for my gaugectrl properly .Is following a wrong way to access it ?
($scope.players.Tweets).each(function(index, element) {
console.log(element.FAVOURITE_COUNT);
Thanks in Advance
Looks like everything is working. It seems like you are trying to access the objects in the array incorrectly.
I think you want to use Array.forEach
someArray.forEach(function(element, index, array) {
// Do stuff here.
});
I made a simplified version of your code:
var app = angular.module('app', []);
app.controller('myController', function($scope, $q, $http) {
var deferred = $q.defer();
$http.get('http://enlytica.com/RSLivee/rest/census').then(function(data) {
deferred.resolve(data);
});
var promise = deferred.promise;
promise.then(function(data) {
var tweets = [];
var total = 0;
$scope.players = data.data;
($scope.players.Tweets).forEach(function(element) {
console.log(element);
tweets.push({FAVOURITE_COUNT: element. FAVOURITE_COUNT, TWEET_ID: element.TWEET_ID});
total += element.FAVOURITE_COUNT;
});
$scope.something.tweets = JSON.stringify(tweets, null, 2);
$scope.something.favoriteTotal = total;
});
$scope.something = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app' ng-controller='myController'>
{{ something.favoriteTotal }}
<pre>{{ something.tweets }}</pre>
</div>

AngularJS copy to clipboard

Is there a way to make a copy button with a copy function that will copy all the contents of a modal and you can paste it to notepad
I needed this functionality in my Controller, as the text to be copied is dynamic, here's my simple function based on the code in the ngClipboard module:
function share() {
var text_to_share = "hello world";
// create temp element
var copyElement = document.createElement("span");
copyElement.appendChild(document.createTextNode(text_to_share));
copyElement.id = 'tempCopyToClipboard';
angular.element(document.body.append(copyElement));
// select the text
var range = document.createRange();
range.selectNode(copyElement);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
// copy & cleanup
document.execCommand('copy');
window.getSelection().removeAllRanges();
copyElement.remove();
}
P.S.
You're welcome to add a comment now telling me how bad it is to manipulate DOM from a Controller.
If you have jquery support use this directive
.directive('copyToClipboard', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.click(function () {
if (attrs.copyToClipboard) {
var $temp_input = $("<input>");
$("body").append($temp_input);
$temp_input.val(attrs.copyToClipboard).select();
document.execCommand("copy");
$temp_input.remove();
}
});
}
};
});
Html
Copy text
if you don't want to add a new library to your project, and you create it by your self, here is a simple, easy solution:
note: I created it with promise functionality (which is awesome)
here is CopyToClipboard.js module file
angular.module('CopyToClipboard', [])
.controller('CopyToClipboardController', function () {
})
.provider('$copyToClipboard', [function () {
this.$get = ['$q', '$window', function ($q, $window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
return {
copy: function (stringToCopy) {
var deferred = $q.defer();
deferred.notify("copying the text to clipboard");
textarea.val(stringToCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = $window.document.execCommand('copy');
if (!successful) throw successful;
deferred.resolve(successful);
} catch (err) {
deferred.reject(err);
//window.prompt("Copy to clipboard: Ctrl+C, Enter", toCopy);
} finally {
textarea.remove();
}
return deferred.promise;
}
};
}];
}]);
that's it, thanks to https://gist.github.com/JustMaier/6ef7788709d675bd8230
now let's use it
angular.module('somthing')
.controller('somthingController', function ($scope, $copyToClipboard) {
// you are free to do what you want
$scope.copyHrefToClipboard = function() {
$copyToClipboard.copy(/*string to be coppied*/$scope.shareLinkInfo.url).then(function () {
//show some notification
});
};
}
and finally the HTML
<i class="fa fa-clipboard" data-ng-click="copyHrefToClipboard($event)"></i>
hope this saves your time
You can use a module I made, ngClipboard. Here's the link https://github.com/nico-val/ngClipboard
You can use either ng-copyable directive, or the ngClipboard.toClipboard() factory.
In HTML:
</img>
In Controller:
$scope.copyToClipboard = function (name) {
var copyElement = document.createElement("textarea");
copyElement.style.position = 'fixed';
copyElement.style.opacity = '0';
copyElement.textContent = decodeURI(name);
var body = document.getElementsByTagName('body')[0];
body.appendChild(copyElement);
copyElement.select();
document.execCommand('copy');
body.removeChild(copyElement);
}
document.execCommand is now deprecated. Instead you can do:
HTML:
<i class="fa fa-copy" ng-click="copyToClipboard('some text to copy')"></i>
Controller:
$scope.copyToClipboard = function(string) {
navigator.clipboard.writeText(string)
.then(console.log('copied!'));
}
try this:
app.service('ngCopy', ['$window', function ($window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
return function (toCopy) {
textarea.val(toCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful)
throw successful;
} catch (err) {
window.prompt("Copy to clipboard: Ctrl+C, Enter", toCopy);
}
textarea.remove();
}
}]);
You need to call this service to your controller. You can do like this:
controllers.MyController = ['$scope', 'ngCopy',
function ($scope, ngCopy) {
ngCopy(copyText);
}];

ng-repeat with checkboxes and capture value

Still new to angular and js. I have a list:
<ul ng-repeat="rate in resources">
<li> <input type="checkbox" ng-model="isSelected" ng-change="appendList(rate)"> </li>
</ul>
When a user clicks on them, i'd like the value to be pushed to a list:
$scope.rateValues = {
'rates': {
'fastrates': {
'value': '',
}
}
};
But I'd like to append a key, value pair to the fastrates like this:
$scope.rateValues = {
'rates': {
'fastrates': {
'value': '100',
'value': '200',
'value': '300',
'value': '400',
}
}
};
I guess i'm stuck on my ng-change function in my controller to handle this. I know this is far from complete but at least the value changes. I need to make it check if it has been added and if so then remove it from the key, value from the object. If it's unchecked and they check it. It needs to create a new 'value': rate pair in the fastrates obj.
$scope.appendList = function(rate){
$scope.rateValues.rates.fastrates.value = rate
}
Here's a plnkr I started http://plnkr.co/edit/MhqEp7skAdejdBRpXx2n?p=info. Any scripting advice on how to accomplish this?
You can't use same key multiple times. You can use array of object.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.resources = {value:['100','200','300', '400']}
$scope.rateValues = {
'rates': {
'fastrates': []
}
};
$scope.appendList = function(rate){
$scope.rateValues.rates.fastrates.push({ value: rate });
}
});
Don't forget to remove value when you uncheck the checkbox.
http://plnkr.co/edit/MhqEp7skAdejdBRpXx2n?p=preview removing value from array when you uncheck checkbox
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.resources = {
value: ['100', '200', '300', '400']
}
$scope.rateValues = {
'rates': {
'fastrates': {
'value': [],
}
}
};
$scope.appendList = function(rate) {
var index = $scope.rateValues.rates.fastrates.value.indexOf(rate);
if (index < 0) {
$scope.rateValues.rates.fastrates.value.push(rate);
} else {
$scope.rateValues.rates.fastrates.value.splice(index, 1);
}
}
});

$watch not updating in ng-repeat

I'm trying to calculate a total by multiplying 2 ng-models.
The models are in a ng-repeat, where I have a own controller for the rows.
On reload, it does the console log, but when I update the ng-models, they don't console log anymore and just don't work.
The controller:
app.controller('RowCtrl', function ($scope) {
$scope.unit_price = 0;
$scope.quantity = 0;
$scope.$watchCollection('[unit_price, quantity]', function(newValues) {
console.log(parseInt(newValues));
}, true);
$scope.total = $scope.unit_price * $scope.quantity;
});
UPDATED with fiddle: http://jsfiddle.net/r9Gmn/
Watch a function that calculates the total:
$scope.$watch(function() {
return unit_price * quantity;
}, function(newVal) {
$scope.total = newVal;
});
I agree with #pixelbits answer.
Just to add that as of angular 1.3 there is a new scope method $watchGroup:
An example http://plnkr.co/edit/2DvSmxUo5l8jAfBrSylU?p=preview
Solution:
$scope.$watchGroup(['unit_price', 'quantity'], function(val) {
$scope.total = val[0] * val[1];
});
Here's your fiddle working: http://jsfiddle.net/mikeeconroy/r9Gmn/1/
In your $scope.rows array on the controller you never defined the properties to be used in the RowCtrl's scope. Also you should make sure you use track by with ng-repeat so you don't get the dupes error.
var app = angular.module('myApp', []);
app.controller('RowCtrl', function ($scope) {
$scope.total = 0;
$scope.$watchCollection('[row.unit_price, row.quantity]', function(newValues) {
$scope.total = parseInt(newValues[0]) * parseInt(newValues[1]);
});
});
app.controller('MainCtrl', function ($scope) {
$scope.rows = [
{ unit_price: 10, quantity: 0 },
{ unit_price: 12, quantity: 0 },
{ unit_price: 15, quantity: 0 },
];
});
This should work fine (if implemented correctly), i.e. your logic is correct:
<div ng-controller="myCtrl">
Unit price:
<input type="number" ng-model="unit_price" />
<br />
Quantity:
<input type="number" ng-model="quantity" />
<hr />
Total: {{total}}
</div>
app.controller('myCtrl', function ($scope) {
$scope.unit_price = 0;
$scope.quantity = 0;
$scope.$watchCollection('[unit_price, quantity]', function(newValues) {
$scope.total = $scope.unit_price * $scope.quantity;
});
});
See, also, this short demo.

Single Controller for multiple html section and data from ajax request angularjs

I'm trying to show two section of my html page with same json data, i don't want to wrap both in same controller as it is positioned in different areas. I have implemented that concept successfully by using local json data in "angular service" see the demo
<div ng-app="testApp">
<div ng-controller="nameCtrl">
Add New
Remove First
<ul id="first" class="navigation">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
</div>
<div>
Lot of things in between
</div>
<ul id="second" class="popup" ng-controller="nameCtrl">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
JS
var testApp = angular.module('testApp', []);
testApp.service('nameService', function($http) {
var me = this;
me.mynames = [
{
"name": "Funny1"
},
{
"name": "Funny2"
},
{
"name": "Funny3"
},
{
"name": "Funny4"
}
];
//How to do
/*this.getNavTools = function(){
return $http.get('http://localhost/data/name.json').then(function(result) {
me.mynames = result.mynames;
return result.data;
});
};*/
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
$scope.mynames = nameService.mynames;
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
)
$scope.addName = function() {
nameService.addName();
}
$scope.removeName = function() {
nameService.removeName();
}
});
jsfiddle
Next thing i want to do is to make a http request to json file and load my two section with data, and if i add or remove it should reflect in both areas.
Any pointers or exisisitng demo will be much helpful.
Thanks
The reason why only one ngRepeat is updating is because they are bound to two different arrays.
How could it happen? It's because that you have called getNavTools() twice, and in each call, you have replaced mynames with a new array! Eventually, the addName() and removeName() are working on the last assigned array of mynames, so you're seeing the problem.
I have the fix for you:
testApp.service('nameService', function($http) {
var me = this;
me.mynames = []; // me.mynames should not be replaced by new result
this.getNavTools = function(){
return $http.post('/echo/json/', { data: data }).then(function(result) {
var myname_json = JSON.parse(result.config.data.data.json);
angular.copy(myname_json, me.mynames); // update mynames, not replace it
return me.mynames;
});
};
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
// $scope.mynames = nameService.mynames; // remove, not needed
nameService.getNavTools().then(function() {
$scope.mynames = nameService.mynames;
});
/* Remove, not needed
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
);
*/
$scope.addName = function() {
nameService.addName();
};
$scope.removeName = function() {
nameService.removeName();
};
});
http://jsfiddle.net/z6fEf/9/
What you can do is to put the data in a parent scope (maybe in $rootScope) it will trigger the both views ,And you don't need to $watch here..
$rootScope.mynames = nameService.mynames;
See the jsFiddle

Resources