Angularjs ng-repeat iterate by 2 - angularjs

I have a for loop in my MVC application like this
for(var i = 0; i < data.length; i +=2){
<div class='#(i== 0? "item active": "item")'>
<div>
#Html.Raw(data[i].Description)
</div>
<div>
#Html.Raw(data[i + 1].Description)
</div>
</div>
}
I want to convert the above code in angularjs.
Means every loop render the record from current and next array index, say i = 0 then render first and second record detail.
Actually it is big object, for clarity I reduce the code, I want to write the same code in ng-repeat
See the fiddle

I end up with a dirty trick:
<div ng-repeat="item in data"
ng-class="{active: $first}" class="item row"
ng-if='$index % 2 == 0'>
<div class='col-lg-6'>{{ item.a }}</div>
<div class='col-lg-6'>{{ data[$index + 1].a }}</div>
</div>
If $index % 2 == 0 only then render, means 0, 2, 4 .. it work as I want.
See to codepen.

You essentially want something like this:
<div ng-repeat="dataEntry in data" ng-class="{active: $first}" class="item">
<div>{{ dataEntry.Description }}</div>
<div ng-if="!$last">{{ data[$index + 1].Description }}</div>
</div>
Use ng-repeat to loop over your data entries
Use ng-class to only apply 'active' class to the first entry (you have access to $first, $last, $even, and $odd, (which are booleans) inside of an ng-repeat scope)
dataEntry represents each entry for each iteration of your data. Use {{ }} to access and render it's contents
You can use $index + 1 to grab the next entry in the array of entries.
I would assume you know that data in this scenario has to be attached / accessible from your $scope.

Related

Using ng-if on a parent ng-repeat

I'm starting at front-end development and there´s something that I don't know if it's possible to do using AngularJS and ng-repeat.
I have an array with 3 levels of data so the first ng-repeat lists the level 1, inside it there's another ng-repeat that lists the level 2 anda at last another one that lists level 3. Something like this:
<div ng-repeat="item-1 in level-1">
<div ng-repeat="item-2 in level-2">
<div ng-repeat="item-3 in level-3">
{{item-3.name}} : {{item-3.valid}}
</div>
</div>
</div>
What I wan't to know if it´s possible to use the ng-if directive on the first level repeat but with a condition of the tird level repeat, something like this:
<div ng-repeat="item-1 in level-1" ng-if="item-3.valid == true">
<div ng-repeat="item-2 in level-2">
<div ng-repeat="item-3 in level-3">
{{item-3.name}} : {{item-3.valid}}
</div>
</div>
</div>
Thank you!
What about moving this logic to the controller managing this HTML. For example something like:
$scope.toBeDisplayedItems = [..];
$scope.level1 = [..];
$scope.level2 = [..];
$scope.level3 = [..];
for (var item1 in $scope.level1) {
for (var item2 in $scope.level2) {
for (var item3 in $scope.level3) {
// do something with $scope.level1[item1] $scope.level2[item2] $scope.level3[item3]
// then fill the candidate array to be used in the HTML
$scope.toBeDisplayedItems.push(....);
}
}
}
In your HTML:
<div ng-repeat="item in toBeDisplayedItems">
{{item.name}} : {{item.valid}}
</div>
By the way I didn't get your check on item-3 in top level of first loop, is that actually working?
Anyway I answered you on the way it's done and not on the how.

Geting incorrect $index value for parent ng-repeat loop

I have following code and try to use $index in delete function but it gives incorrect value of it.
<li ng-repeat="joinMember in data.teamMember | orderBy:'member.screenName || member.fname' ">
<div class="member-list-img">
<a ng-href="">
<img ng-src="{{joinMember.member.data.image ? (joinMember.member.data.imageType == 'avatar' ? '/public/images/avatars/' + joinMember.member.data.image : '/public/images/' + joinMember.member.data.image) : '/public/images/avatars/avatar-73.png'}}" width="100%" alt="{{joinMember.member.screenName ? joinMember.member.screenName : joinMember.member.fname + ' ' + joinMember.member.lname }}" />
</a>
</div>
<div class="member-list-cont">
<h4>
<a ng-href="#">
{{joinMember.member.screenName ? joinMember.member.screenName : joinMember.member.fname + ' ' + joinMember.member.lname }}
</a>
</h4>
<span>{{joinMember.created | date : "MMMM d, y"}}</span>
</div>
<div ng-if="data.canModify" class="membr-delete">
<a ng-href="">
<i class="fa fa-trash text_link" aria-hidden="true" ng-click="deleteTeamMember($parent.$index, joinMember.id)"></i>
</a>
</div>
</li>
That's because the directive ng-if creates a new scope for itself, when you refer to $parent, it access the immediate $parent's scope, i.e., the inner repeat expression's scope.
So if you want to achieve something you wanted like in the former, you may use this:
<div ng-repeat="i in list">
<div ng-repeat="j in list2">
<div ng-if="1">
({{$parent.$parent.$index}} {{$parent.$index}})
</div>
</div>
</div>
if you have more than one inner directives, you can use ng-init for storing $index in a variable for references in child scopes.
<div ng-repeat="i in list" ng-init="outerIndex=$index">
<div ng-repeat="j in list2" ng-init="innerIndex=$index">
<div ng-if="1">
({{outerIndex}} {{innerIndex}})
</div>
</div>
</div>
So try $parent.$parent.$index in your example and please check understanding the scopes
You are using $parent.$index in a div that have ng-if tag. which delete dom element(div) if condition is fall so that case you will receive incorrect $index value. but with ng-show it only add hide class to that div.
So try to ng-show if it is not important to remove div element instead just hide it.
Note:- You are also using orderBy filter in ng-repeat which will sort in only your DOM so if you will find incorrect object value in your controller.
As you can see in the official documentation of angularjs you should get a zero-based index via $index within a ng-repeat. Try the example by angularjs here. Try to debug data.teamMember in your controller to make sure that this is the correct array you'd like to iterate.

Angular js - how to increment in html based on condition

I am using angular repeat to populate form's fields dynamically. There is a scenario where I need to to notify user(show ! icon for duplicate fields). Below is code snippet:
<div ng-init="counter = 0">
<div ng-repeat="item in list track by $index">
<div ng-show="{{item.show}}">{{counter+1}}</div>
</div>
<div ng-show="{{counter > 1}}"> ! </div>
</div>
Counter variable only increment if its used like {{counter + $index}}, can it be possible without $index?
Assigning variables inside html is not officially supported.
But there is always a hack for what you asked:
<div ng-init="counter = 0"></div>
<div ng-repeat="n in [1,2,3,4,5]">
<div style="display:none;">{{ n == 3 ? counter = "World!" : counter = n }}</div>
<p>Hello {{ counter }}</p>
</div>
Notice that I used a non-displayed div for assigning the "counter" conditionally.
Output:
Hello 1
Hello 2
Hello World!
Hello 4
Hello 5
Answer to the 1st comment:
When counter == 3, we divide it by 2.
<div ng-init="counter = 0"></div>
<div ng-repeat="n in [1,2,3,4,5]">
<div style="display:none;">
{{ counter = n }}
{{ counter == 3 ? counter = counter / 2 : counter = counter }}
</div>
<p>Hello {{ counter }}</p>
</div>
Output:
Hello 1
Hello 2
Hello 1.5
Hello 4
Hello 5
Answer to the 3rd comment:
I finally understood what you asked. Let me change the way to approach by using ng-if to keep the record of counter. I used ng-init to increment the counter when n is divisible by 2. You need to call $parent.$parent.counter to reach the original counter otherwise ng-if will create its own counter inside the child scope.
JSFiddle
<div ng-init="counter = 0"></div>
<div ng-repeat="n in [2,6,5,6,8,9,11] track by $index">
<!-- ngRepeat child scope -->
<div ng-if="n % 2 == 0"
ng-init="$parent.$parent.counter = $parent.$parent.counter + 1"
style="display:none;">
<!-- ngIf also creates a child scope -->
</div>
</div>
<p>Counter = {{ counter }}</p>
Output:
Counter = 4

How to bind array with ng-bind-html directive in angularJS?

I want to show for every item different description.
This is the controller:
todoApp.controller('todos',function($scope,todoFactory){
todoFactory.getTodos().success(function (data) {
courses = x2js.xml_str2json(data);
$scope.todos = courses.rss.channel.item;
for(var i = 0 ; i < $scope.todos.length ; i++){
item = $scope.todos[i];
console.log(item.description);
$scope.message = item.description;
}
});
this is the html:
<div ng-controller="todos" class="list" style="padding-top: 8%">
<div class="list card" ng-repeat="todo in todos | filter:search" >
<div class="item item-avatar" ng-click="openLink(todo.link)" >
<img src="Bla-Bla-Logo-1.png">
<h2>{{todo.title}}</h2>
<p>{{todo.pubDate | limitTo:25 }}</p>
</div>
<div class="item item-body">
<p ng-bind-html="message"></p>
<p>
1 Like
5 Comments
</p>
</div>
</div>
<!--end list card-->
</div>
<!--end todos-->
Just to explain the code I get xml and convert into json so todos is array of objects.
Message is entering every object and get the description (but in the description has tags so i use ng-bind-html directive to show it properly).
I understand that $scope.message will hold just the last description. How to make it to belong in the ng-repeat so I can get different description for different item?
Thanks.
replace
<p ng-bind-html="message"></p>
with
<p ng-bind-html="todo.description"></p>
please provide the data which is you want to displayed repeatedly.
How data is represented.You are getting last one because it is overriding.
The "ngBind" attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
Typically, you don't use "ngBind" directly, but instead you use the double curly markup like {{ expression }} which is similar but less verbose.

Angularjs - How to keep count of total iterations across nested ng-repeat in the template

I have a fairly large object that needs to be iterated over in nested ng-repeat loops
A simplified version looks like this:
{{totalEvents = 0}}
<div ng-repeat="(mainIndex, eventgroup) in EventsListings">
<ul>
<li ng-repeat="event in eventgroup.events" ng-click="Current(totalEvents)">
<div class="event-item-container" ng-show="eventDetailsView[totalEvents]">
{{totalEvents = totalEvents + 1}}
</div>
</li>
</ul>
</div>
{{totalEvents = 0}
How can I keep track of totalEvents counter value.. How can I get a total number of iterations across nested loops IN the template?
you can reach many value just using $index property of ng-repeat...
HTML
<div ng-repeat="eventgroup in EventsListings" ng-init="outerIndex = $index">
<ul>
<li ng-repeat="event in eventgroup.events" ng-click="Current(totalEvents)">
<div class="event-item-container">
{{event.name}} can have unique value like
<br/>(outerIndex) * (eventgroup.events.length) + innerIndex
<br/>Total Events = {{outerIndex * eventgroup.events.length + $index}}
<br/>Inner Events = {{$index}}
</div>
</li>
</ul>
</div>
here is working PLUNKER
UPDATE
After some times and some comments I realized that my code is not calculating total iterations correctly, so I made some changes to fix it.
First mistake I made somehow I thought event numbers will be equals for every set, second one if there are more than 2 sets again it fails.
So for keeping track of total iterations I set an array which is called totalIterations in code. In this array I set total number events we already iterate so far,
For example at the finish of first set it will be length of first event group and for second it will be first and second group, and so on... For achieving this I used ng-repeat-end directive here is the final code
<div ng-repeat="eventgroup in EventsListings" ng-init="outerIndex = $index">
<ul>
<li ng-repeat="event in eventgroup.events">
<div class="event-item-container">
{{event.name}} can have unique value like
<br/>Total Events Count = {{totalIterations[outerIndex- 1] + $index}}
<br/>Innder Events = {{$index}}
</div>
<button class="btn btn-success" ng-click="Current({{totalIterations[outerIndex- 1] + $index}})">Current Event</button>
</li>
<span ng-repeat-end ng-init="totalIterations[outerIndex] = totalIterations[outerIndex - 1] + eventgroup.events.length"></span>
</ul>
</div>
and here is latest PLUNKER
I want to suggest different way to approach this, I think it's pretty cool and easy :
In the template :
<ul>
<div ng-repeat="group in obj.objectGroups">
<li>{{group.name}}</li>
<li ng-repeat="item in group.items" ng-init="number = countInit()">
Total = {{number + 1}}
</li>
</div>
</ul>
In the controller :
$scope.totalCount = 0;
$scope.countInit = function() {
return $scope.totalCount++;
}
If you really want the template to drive this calculation, you could keep a counter in the Controller and create a function that increments that counter. Then call that function from the template.
Honestly, though, it seems very strange to put this sort of logic in the view. It would make much more sense just to do a recursive count in pure Javascript in the Controller.

Resources