Workaround for error 10 $digest() iterations reached - angularjs

I am displaying data from the database (using Web API) on the page:
<div ng-repeat="Item in Items">
<div class="row">
<div class="col-sm-3">{{Item.Id}}</div>
<div class="col-sm-3">{{Item.Desc)}}</div>
<div class="col-sm-6">{{Item.CollectionID}}</div>
</div>
</div>
the above works fine, but when I try getting actual Collection Name, I get an issue:
<div ng-repeat="Item in Items">
<div class="row">
<div class="col-sm-3">{{Item.Id}}</div>
<div class="col-sm-3">{{Item.Desc)}}</div>
<div class="col-sm-6">{{GetCollectionName(Item.CollectionID)}}</div>
</div>
</div>
here is my controller function for getting Collection Name:
$scope.GetCollectionName = function (CollId) {
$http.get('http://Server/App/api/GetCollName/' + CollId).
then(function (result) {
$scope.CollectionName = result.data;
return $scope.CollectionName;
});
}
is there a better way to do this besides modifying my underlying query?

The basic idea here is to use ng-init to initialize a local CollectionName variable for each Item in your ng-repeat. You can then use that local variable to output CollectionName[Item.CollectionID].
Here's a working demo
<div ng-repeat="Item in Items" ng-init="GetCollectionName(Item.CollectionID)">
<div class="row">
<div class="col-sm-3">{{Item.Id}}</div>
<div class="col-sm-3">{{Item.Desc)}}</div>
<div class="col-sm-6">{{CollectionName[Item.CollectionID]}}</div>
</div>
</div>
$scope.CollectionName = [];
$scope.GetCollectionName = function (CollId) {
$http.get('http://Server/App/api/GetCollName/' + CollId)
.then(function (result) {
$scope.CollectionName[CollId] = result.data;
});
}

It is bad practice to call the function inside loop. And you are using expression tag in angularjs which creates watcher. Always make sure all the necessary records to display is already in the associated scope variable.

$scope.GetCollectionName = function (CollId) {
if(!$scope.someDataCheck[CollId] && !$scope.someData[CollId]){
$scope.someDataCheck[CollId] = true;
$http.get('http://Server/App/api/GetCollName/' + CollId).
then(function (result) {
$scope.someDataCheck[CollId] = false;
$scope.someData[CollId].data = result.data;
});
}
return $scope.someData[CollId];
}

Related

post.length stays 0 due to loop - AngularJS

I'm trying to add pagination but I can't seem to figure out this last part.
Everything is setup, though my pagination isn't recording the amount of posts that are linked with the user.
Seeing that I'm doing a forEach and if loop and pushing the retrieved items into a empty collection, my 'posts.length' is returning 0.
Hence the pagination only showing page 1/1 and not 1/2 (for example).
Here is my full code:
profileCtrl.js
Here is the $http.get - I'm trying to get all the posts that the logged in user made doing this loop:
app.controller('profileCtrl', function($scope, auth, $http, $log) {
$scope.auth = auth;
$scope.date = auth.profile.created_at;
$scope.pageSize = 5;
$scope.posts= [];
$http.get('URL')
.then(function(result) {
angular.forEach(result.data, function(data, key) {
if(data.userId === auth.profile.user_id) {
$scope.posts.push(data);
}
});
});
});
profile.html
As you can see, I'm trying to get the length of post in posts using total-items="posts.length":
<div class="col-md-8 no-padding-right">
<div class="panel panel-primary">
<div class="list-group-item active text-center">
<h4 class="no-margin-top no-margin-bottom">Recent Activity</h4>
</div>
<a href="#" class="list-group-item" ng-repeat="post in posts| startFrom: (currentPage - 1) * pageSize | limitTo: pageSize | orderBy :'created_at':true">
<div class="row">
<div class="col-md-4">
<div class="thumbnail no-border no-margin-bottom">
<img src="https://placehold.it/150x150" alt="bird" width="150" height="150"/>
</div>
</div>
<div class="col-md-8">
<h4 class="no-margin-top no-margin-bottom"><strong>{{post.birdname}}</strong></
</div>
</div>
</a>
<uib-pagination total-items="posts.length" ng-model="currentPage" max-size="pageSize" boundary-link-numbers="true"></uib-pagination>
</div>
</div>
app.js
I also added a filter in app.js:
app.filter('startFrom', function() {
return function(data, start) {
return data.slice(start);
}
});
When I console.log(posts.length); I keep getting 0 and I'm guessing it's because of the $scope.posts = []; declared on top (profileCtrl.js).
Edit:
After doing a bit of debugging with console.log, I do get the value given when doing this:
$http.get('url')
.then(function(result) {
angular.forEach(result.data, function(data, key) {
if(data.userId === auth.profile.user_id) {
$scope.posts.push(data);
}
});
console.log($scope.posts.length);
});
How should I fix this?
If you're waiting for data to be returned before loading the collection (with pagination) either add a ng-if="posts.length" to the container, or initialise $scope.posts as being null and add ng-if="posts" if you want the list to show when the API returns 0 results. This will prevent Bootstrap's pagination directive being parsed until the data it needs is available.
Edit: After debugging, the following plunkr contains a working implementation: http://plnkr.co/edit/VQjNVK6gRKsCqxVb54nR?p=preview

I keep on getting TypeError: v2.CurrentTaskForce is not a function

Left hand side of the page is displaying list of task force.
On click of the list item related data is to be displayed on right hand side.
When I click on the list item, first time it works fine. It displays the task force name as a header in right hand side panel. When I click on another list item it gives TypeError: v2.CurrentTaskForce is not a function
var VirtualDir = GetVirtualDirectory();
angular.module('MyApp',[])
.controller('TaskForceController', function ($scope, TaskForceService) { // inject taskforce service
$scope.TaskForceList = null;
//$scope.CurrentTaskForce = {}
TaskForceService.GetTaskForceList().then(function (d) {
$scope.TaskForceList = d.data;
}, function () {
alert('failed');
});
$scope.CurrentTaskForce = function (item) {
angular.forEach($scope.TaskForceList, function (value, index) {
value.IsActive = false ;
})
item.IsActive = true;
alert("s");
$scope.CurrentTaskForce = item;
}
})
.factory('TaskForceService', function ($http) { //here factory is created which is a populer way to create and configure services
var fac = {};
fac.GetTaskForceList = function () {
return $http.get(VirtualDir + '/TaskForce/GetMyTaskForce/');
}
return fac;
});
<div class="container-fluid" ng-controller="TaskForceController as tf">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar" >
<%-- <li class="active">Overview <span class="sr-only">(current)</span></li>--%>
<li ng-repeat="item in TaskForceList" ng-class="{active: item.IsActive == true}" ng-click="CurrentTaskForce(item)" ><a href="#" >{{item.TaskForce}}</a></li>
</ul>
</div>
<div class="col-sm-9 co-md-9" style="left:20%">
<div class="panel panel-default" ">
<div class="panel-heading">
<p class="panel-title">{{CurrentTaskForce.TaskForce}}</p>
<!--ng-repeat="curritem in CurrentTaskForce"-->
</div>
</div>
</div>
</div>
</div>
While copying item to CurrentTask force instead of
$scope.CurrentTaskForce = item;
I used
angular.copy(item, $scope.CurrentTaskForce);
It is happening because CurrentTaskForce is defined as a function and a variable in same controller. Please use a different name for either.

pass Angular variables to Laravel

I load data via Angular ajax. How can I pass returned results to laravel #include partial?
Angular:
$scope.findItem = function(itemId) {
$scope.spinner = true;
$http.get('item/' + itemId).success(function(results) {
$scope.spinner = false;
$scope.results = results[0];
});
};
html:
<div ng-init="findItem(185)">
<span ng-show="spinner" class="spinner"></span>
<div ng-hide="results == undefined">
#include('partials.item', {{ results }}) // <- I want to pass 'results' here
</div>
</div>
You can't really do that. But you can just include the results variable as javascript in your partials.item view. So your HTML would look like this:
<div ng-init="findItem(185)">
<span ng-show="spinner" class="spinner"></span>
<div ng-hide="results == undefined">
#include('partials.item')
</div>
</div>
And your partials.item view would have angular variables instead of laravel variables:
#{{results}}
Instead of
{{$results}}
Make sense?

AngularJS: ng-repeat is listing thousands of elements when there should be none

I've searched for issues similar to this but have found none. I have a service which does a $http get for a list of items, and a controller which calls that service and binds the list to $scope. On my page I use ng-repeat to list the items but for some strange reason it's listing 2473 items, even though there's none in the database.
service.js
getTickits : function() {
var deferred = $q.defer();
$http.get('/api/tickits').success(function(data){
deferred.resolve(data);
})
.error(function(data){
deferred.reject(data);
});
return deferred.promise;
}
controller.js
$scope.tickits = [];
$scope.getTickits = function(){
TickitService.getTickits().then(function (data) {
$scope.tickits = data;
})
}
$scope.getTickits();
Then on my page:
<div id = "tickit-list" class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="panel panel-primary" ng-repeat="tickit in tickits track by $index">
<div class="panel-heading">
<h4>Title: {{ tickit.title }}</h4>
</div>
<div class="panel-body">
<p>Description: {{ tickit.description }}</p>
</div>
<div class="panel-footer">
Delete tickit
</div>
</div>
</div>
</div>
The reason I added 'track by $index' is because without that I get an error on the chrome console saying 'Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys'.
I really don't know how it thinks there are over 2 thousand items so if anyone has any ideas it would be very helpful, thanks!

Looping though an object in Angular and using the key inside a ng-show

i am creating a simple Angular.js tabbing box which changes the box that is active accoring to a value 'tab' that is used inside ng-show on the elements.
This is working fine, however, at the moment I am writing all the HTML statically and I would rather cut down my code into a simple ng-repeat loop to loop through all the divs.
This is easy enough in PHP as I would use a foreach loop and use the key to generate the tab number, I just can't seem to do this in Angular. Here is my code at the moment:
<div id="services-box-nav">
<ul>
<li>Rewards</li>
<li>Community</li>
<li>Partners</li>
<li>Jobs</li>
<li>Volunteering</li>
<li>Feedback</li>
<li>Gallery</li>
</ul>
</div>
<div id="services-content-boxes">
<div ng-show="tab == 1">
<div class="row">
<div class="col-md-12">
<h3>{{serviceBoxes.rewards.title}}</h3>
</div>
</div>
<div class="row">
<div class="col-md-5">
{{serviceBoxes.rewards.text}}
</div>
<div class="col-md-7">
</div>
</div>
</div>
<div ng-show="tab == 2">dwd</div>
<div ng-show="tab == 3">d</div>
<div ng-show="tab == 4">df</div>
<div ng-show="tab == 5">gr</div>
<div ng-show="tab == 6">r</div>
<div ng-show="tab == 7">rg</div>
</div>
controller('servicesController', function($scope, $location, joomlaService) {
$scope.serviceBoxes = {};
joomlaService.getArticleDetails(21).then(function(articleReturnData) {
$scope.serviceBoxes.rewards = articleReturnData;
});
joomlaService.getArticleDetails(22).then(function(articleReturnData) {
$scope.serviceBoxes.community = articleReturnData;
});
joomlaService.getArticleDetails(23).then(function(articleReturnData) {
$scope.serviceBoxes.partners = articleReturnData;
});
joomlaService.getArticleDetails(24).then(function(articleReturnData) {
$scope.serviceBoxes.jobs = articleReturnData;
});
joomlaService.getArticleDetails(25).then(function(articleReturnData) {
$scope.serviceBoxes.volunteering = articleReturnData;
});
joomlaService.getArticleDetails(26).then(function(articleReturnData) {
$scope.serviceBoxes.feedback = articleReturnData;
});
joomlaService.getArticleDetails(27).then(function(articleReturnData) {
$scope.serviceBoxes.gallery = articleReturnData;
});
});
What I want to do is loop through the serviceBoxes object and dynamically create the ng-show condition (tab == i) using the key, which should increment each time (1, 2, 3, 4, etc). I don't know how I go about this using Angular. It would cut down my code considerably so feel it is necessary.
Can anyone point out how this is done?
Thanks
You can use angular-ui bootstrap Tabset directive.
<tabset>
<tab ng-repeat="serviceBox in serviceBoxes" heading="{{serviceBox.title}}" active="serviceBox.active">
{{serviceBox.text}}
</tab>
</tabset>
Thus your view is clean and tidy.
And your controller will look like:
controller('servicesController', function($scope, $location, joomlaService) {
$scope.serviceBoxes = [];
joomlaService.getArticleDetails(21).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(22).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(23).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(24).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(25).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(26).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
joomlaService.getArticleDetails(27).then(function(articleReturnData) {
$scope.serviceBoxes.push(articleReturnData);
});
});
<ul>
<li ng-repeat="serviceBox in serviceBoxes">{{serviceBox.title}}</li>
</ul>
<div ng-repeat="serviceBox in serviceBoxes" ng-show="tab == {{selectedIndex}}">{{serviceBox.contents}}</div>
In your controller:
$scope.selectedIndex = 0; // Default selected index, use -1 for no selection
$scope.itemClicked = function ($index) {
$scope.selectedIndex = $index;
};
The ng-repeat directive loops through every element and makes a copy of the html element it's placed inside of. If there at 10 items to look through, you will have 10 html elements. It also you references to the index of the current element via $index.
ng-click will call the function on itemClicked(), passing in the current index through the $index reference that ng-repeat supplied. In our function we're using that parameter to set our $scope.selected to it.
I have tried creating something similar. Try below code
I have hardcoded mapTab array.You can populate myTab using the corresponding values from $scope
In controller-
$scope.tab;
$scope.mapTab=[{},{"1": "dwd"},{"2":"d"},{"3":"dwd"},{"4":"df"},{"5":"gr"},{"6":"r"},{"7":"rg"}];
In html--
<div ng-repeat="(key,val) in mapTab">
<div ng-repeat="prop in val">
<div ng-show="tab==key">{{prop}}</div>
</div>
</div>
</div>
Demo--http://jsfiddle.net/RahulB007/HB7LU/9348/

Resources