ng-repeat is repeating multiple time with same array - javascript

ng-repeat is binding same array with multiple times.
js :
$scope.currentitem = item;
$scope.currentitemCategory = $scope.currentitem.category.split(',');
console.log($scope.currentitemCategory);
html:
<div ng-repeat="category in currentitemCategory track by $index">
<a href="/content/digital-library/us/en/search.html?category={{category}}">
<span class="text"> {{category}} </span>
</a>
</div>
console :
Categorized in
audience/business
audience/business
audience/business
brandguidelines
brandguidelines
brandguidelines
corporateinitiatives/idf
corporateinitiatives/idf
corporateinitiatives/idf

I've created a sample application with your given snippet. I do not see any repeated entries. Everything works fine. Please provide few more details if the issue really exists.
var app= angular.module('sample', []);
app.controller('samplecontroller', function($scope){
var item = {category: 'Tennis, Carroms, Soccer, Volleyball'};
$scope.currentitem = item;
$scope.currentitemCategory = $scope.currentitem.category.split(',');
console.log($scope.currentitemCategory);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="sample">
<div ng-controller="samplecontroller">
<div ng-repeat="category in currentitemCategory track by $index">
<a href="/content/digital-library/us/en/search.html?category={{category}}">
<span class="text"> {{category}} </span>
</a>
</div>
</div>
</body>

Related

Angular active ng-class isn't working properly

I have some angular code that is supposed to assign a class to only the parent element of the link clicked. This seems to work initially, but then after clicking around a bit, the code seems to get stuck. Here is some sample code of what I'm working with:
<div ng-repeat="item in items track by item.id" class="row" ng-class="{'active': selectItem.this == item.id}">
<a ng-click="selectItem.this = item.id">Move to top</a> {{item.name}}
$scope.selectItem = { this: -1 };
http://plnkr.co/edit/jhahff7OyVTVt615BBp3?p=preview
Any help would be great!
You just need to make the whole text a clickable DOM
<div ng-repeat="item in items track by item.id" class="row" ng-class="{'active': selectItem.this == item.id}">
<a ng-click="selectItem.this = item.id">Move to top <span ng-bind="item.name"></span></a>
</div>
I replaced the a tag with p tag and bind an click event to the p tag. With this refactoring, I don't see any lagging or weird behaviour.
<body ng-controller="MainCtrl">
<div ng-repeat="item in items track by item.id" class="row"
ng-class="{'active': selectItem.this == item.id}">
<p style="cursor: pointer;" ng-click=selectedItem()>
Move to top {{item.name}}
</p>
</div>
</body>
In controller
$scope.selectItem = {};
$scope.selectedItem = function () {
$scope.selectItem.this = this.item.id;
};
Let me know if you still see any issues.

Angular - Error: ngRepeat:dupes Duplicate Key in Repeater

I am working on a simple todo app that adds task to an existing array of json data. However when I try to add more than one task I get this error: Error: [ngRepeat:dupes]. I can't for the life of me figure out what is going wrong. I suspect it might have something to do with the namespace, but after changing names around a few times I still get the same error. If anybody could point me in the right direction I would much appreciate it.
The HTML Code
<div id="taskComplete" ng-app="taskComplete">
<div class="container" ng-controller="taskCtrl">
<div id="taskCompleteHeading" class="row">
<div class="col-xs-12">
<div class="page-header">
<h1 class="text-center">TaskComplete <small>An AgularJs App</small></h1>
</div>
</div>
</div>
<div id="newTaskSubmit">
<input type="text" ng-model="newTask.title">
<input type="text" ng-model="newTask.description">
<button type="button" ng-click="addTask(newTask)">Add Task</button>
</div>
<div class="well">
<pre>{{newTask | json}}</pre>
</div>
<div ng-repeat="task in activeTasks">
<h4>{{task.title}}</h4>
</div>
</div>
</div>
UPDATED SOLUTION
<div ng-repeat="task in activeTasks track by $index">
<h4>{{task.title}}</h4>
</div>
The JAVASCRIPT Code
angular
.module('taskComplete')
.controller('taskCtrl', function($scope, taskFactory) {
$scope.activeTasks;
taskFactory.getTasks().success(function(data) {
$scope.activeTasks = data;
console.log($scope.activeTasks);
}).error(function(error) {
console.log(error);
});
$scope.newTask = {};
$scope.addTask = function(newTask) {
$scope.activeTasks.push(newTask);
}
});
Use this
<div ng-repeat="task in activeTasks track by $index">
<h4>{{task.title}}</h4>
</div>
So angular will track your ng-repeat node
Use track by $index:
ng-repeat="task in activeTasks track by $index"
$scope.addTask = function(newTask) {
$scope.activeTasks.push(newTask);
}
Should become
$scope.addTask = function(newTask) {
$scope.activeTasks.push(newTask);
$scope.newTask = {};
}
The error was caused by the same object being used twice. It is also why changes below were being mirrored by the added task.

AngularJS $index always 0

i am having a problem with angularjs and $index
i give it at a parameter to a function. It works at HTML in {{}} ({{$index}} works). But it doesnt work in the function. I alert the index and its always 0...
I used it at another position in my project and it works fine..
Here is the code.
<input type="checkbox" id="rounded1" ng-click="setClickEvent($index)" ng-model="clickStatus"/>
JS File with the function:
$scope.setClickEvent = function(index) {
alert(index);
};
the alert is always 0....
i hope someone could help me. Thanks :)
It looks like you're not using this <input> tag in an ng-repeat directive. $index will show 0 unless it's used in an ng-repeat where it will count from 0 to n.
Perhaps you meant to do something like this:
<div ng-repeat="i in [1, 2, 3, 4, 5] track by $index">
<input type="checkbox" ng-click="setClickEvent($index)" ng-model="clickStatus"/>
</div>
I removed the ID because each of the 5 checkboxes would have the same ID which isn't valid.
Sorry, here is the whole html code with the ng-repeat
<div ng-repeat="frage in frageListe">
<div class="input-group">
<div class="container-fluid list-group-item ">
<div class="rounded">
<input type="checkbox" id="rounded1" ng-click="setClickEvent(frage.id)" ng-model="clickStatus"/>
<label for="rounded1"></label>
</div>
<div class="list-text">
<h3 class="list-group-item-heading quest-list-text serif">{{frage.titel}} {{$index}}</h3>
</div>
</div>
</div>
<hr class="divider-line-questlist">
</div>
Not sure if this is relevant, but I had the same problem. For me the issue was that I was nesting multiple ng-repeats. To solve this I set aliases for the indexes with ng-init.
https://docs.angularjs.org/api/ng/directive/ngInit
<script>
angular.module('initExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.list = [['a', 'b'], ['c', 'd']];
}]);
</script>
<div ng-controller="ExampleController">
<div ng-repeat="innerList in list" ng-init="outerIndex = $index">
<div ng-repeat="value in innerList" ng-init="innerIndex = $index">
<span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
</div>
</div>
</div>

AngularJS : Nested controllers not working in ng-include

As per the AngularJS article (have a look in nested controller fragment), I'm trying to implement nested controllers with ng-include
index.html
<body id="spaWrapperApp" ng-app="spaWrapperApp">
<div class="container-fluid" id="wrapper" ng-controller="mainController">
<div class="navigation">
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f1.html')">
<span>Page 1</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f2.html')">
<span>Page 2</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f3.html')">
<span>Page 3</span>
</a>
</div>
<div id="content" >
<div ng-include="currentPage"></div>
</div>
</div>
<script type="text/javascript">
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
console.log($scope);
$scope.requestPage = function(friendlyURL){
console.log(friendlyURL);
$scope.currentPage = friendlyURL;
}
}]);
</script>
</body>
Page1 (code given below)file will injected in ng-include
<div>Testing page include 1</div>
<hr/>
<br/>
<div ng-controller="FirstController">
<p>1# {{ name }}</p>
<div ng-controller="SecondController">
<p>2# {{ name }}</p>
</div>
</div>
<script type="text/javascript">
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
</script>
In the whole case the end result will be nested controller injected in ng-include area.
The issue is when I run that code that time this error is shown to me.
"Error: [ng:areq] Argument 'FirstController' is not a function, got undefined"
Any idea what exactly going wrong ?
Something unexpected going in AngularJS.
If you are using ng-include and try to inject pageX in that area and pageX contains some script, in that case pageX script not executed, for that I just write all the angularJS controllers handler in index.html only and it works fine for me.
like
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
$scope.requestPage = function(friendlyURL){
$scope.currentPage = friendlyURL;
}
}]);
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);

AngularJS ngRepeat element removal

There are quite a few questions on how to implement item removal inside ngRepeat directive, and as I figured out, it comes down to using ngClick and triggering some remove function passing it item's $index.
However, I couldn't find anywhere an example where I have multiple ngRepeats:
<div ng-controller="MyController">
<div ng-repeat="email in user.emails">
{{ email }} <a href>Remove</a>
</div>
<div ng-repeat="phone in user.phones">
{{ phone }} <a href>Remove</a>
</div>
</div>
For this, I would need to create $scope.removePhone and $scope.removeEmail which would be called using ngClick on Remove anchor. But I'm looking for a more generic solution. Especially since I have many pages with many ngRepeats .
I was thinking about writing a directive which would be placed on Remove anchor and would do something like this:
Find ngRepeat among parent elements.
Read what it's iterating over ('user.emails' in first case, 'user.phones' in second)
Remove $index element from THAT model.
So the markup would look something like this:
<div ng-controller="MyController">
<div ng-repeat="email in user.emails">
{{ email }} <a href remove-directive="$index">Remove</a>
</div>
<div ng-repeat="phone in user.phones">
{{ phone }} <a href remove-directive="$index">Remove</a>
</div>
</div>
Is what I'm looking for possible to achieve and what would be the preferred way to do this?
Current hacky solution
Here is how I do it currently. It's hacky and ugly but gets the job done until I figure out a prettier way.
myAppModule.controller('MyController', function ($scope, $parse, $routeParams, User) {
$scope.user = User.get({id: $routeParams.id});
$scope.remove = function ($index, $event) {
// TODO: Find a way to make a directive that does this. This is ugly. And probably very wrong.
var repeatExpr = $($event.currentTarget).closest('[ng-repeat]').attr('ng-repeat');
var modelPath = $parse(repeatExpr.split('in')[1].replace(/^\s+|\s+$/g, ''));
$scope.$eval(modelPath).splice($index, 1);
};
});
And in DOM:
<div ng-repeat="email in user.email" class="control-group">
<label class="control-label">
{{ "Email Address"|_trans }}
</label>
<div class="controls">
<input type="text" ng-model="email.address">
<span class="help-inline"><a href ng-click="remove($index, $event)">{{ "Delete"|_trans }}</a></span>
</div>
</div>
You could create a generic remove method that would take in the array and the item to remove.
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }} <a ng-click="remove(emails, $index)">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }} <a ng-click="remove(phones, $index)">Remove</a>
</div>
</div>
$scope.remove = function(array, index){
array.splice(index, 1);
}
No JS
<div ng-repeat="option in options" ng-init=options=[1,2,3,4,5]>
<button ng-click="options.splice($index,1)">Remove me</button>
</div>
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails as datasource">{{ email }}
<a ng-click="datasource.splice($index,1)">Remove</a>
</div>
<div ng-repeat="phone in phones as datasource">{{ phone }}
<a ng-click="datasource.splice($index,1)">Remove</a>
</div>
</div>
A very simple and convenient way that works cross-browser is to use the 'remove' utility method from the library lodash.
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="removeItem(phones, phone)">Remove</a>
</div>
In your controller you declare then
//inject lodash dependency
//declare method in scope
$scope.removeItem = function(list, item){
lodash.remove(list,function(someItem) { return item === someItem});
}
You may of course use indexes if you like. See https://lodash.com/docs#remove
If you have used ng-repeat on an object instead of an array, do the following.
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }}
<a ng-click="remove(emails, email)">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="remove(phones, phone)">Remove</a>
</div>
</div>
$scope.remove = function(objects, o){
delete object[o.id];
}
or the more terse
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }}
<a ng-click="delete emails[email.id]">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="delete phones[phone.id]">Remove</a>
</div>
</div>
presumes that the objects look like this
var emails = { '123' : { id : '123', .... } };
var phones = { '123' : { id : '123', .... } };

Categories