AngularJS - ng-repeat horizontally x number of times, then new line - angularjs

I am trying to perform a simple ng-repeat on an <li>. In the past, i have created vertical ng-repeat. I am now trying to create a horizontal one, however, one that displays 4 items, then starts the ng-repeat again on a new line.
The way i have gone about this is using the grid-wrap technique (CSS) found here: http://builtbyboon.com/blog/proportional-grids
So each <li>, has a CSS class/width of one-quarter (25%).
Is this the correct/Angular way of going about it? Or should i be using some kind of $index on the <li> and triggering a <br> when $index == 3 ?
HTML:
<div ng-controller="MainCtrl">
<ul class="grid-wrap one-whole">
<li ng-repeat="product in Products" class="grid-col one-quarter">
<div class="product-container">
<div>{{ product.ModelNo }}</div>
<img ng-src="{{product.ImgURL}}" width="80%"/>
<div>${{ product.Price }}</div>
</div>
</li>
</ul>
</div>
CSS:
.grid-wrap {
margin-left: -3em;
/* the same as your gutter */
overflow: hidden;
clear: both;
}
.grid-col {
float: left;
padding-left: 3em;
/* this is your gutter between columns */
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.one-quarter {
width: 25%;
}
Here's my plunkr: http://plnkr.co/edit/REixcir0gL0HGCTvclYN?p=preview
Any other improvements you see feel free to add.
Thanks

I did some research and found this answer:
Customize ng-repeat in AngularJS for every nth element
<div class="section">
<div ng-repeat="items in MyList">
<img ng-click="AddPoint($index)" src={{items.image}} />
<span>{{items.currentPoint}}/{{items.endPoint}}</span>
<br ng-if="!(($index + 1) % 4)" />
</div>
So you could use this:
<br ng-if="!(($index + 1) % 4)" />
There doesn't seem to be a better way. You probably can't get around using index.

Related

angualrjs ng-repeat data-toggle issue

I have a below code :`
<DIV class="panel-group" ng-repeat="ent in EntitlementList | unique:'attributename'">
<DIV class="panel panel-default">
<div style="height: 40px; margin-left: 1%; margin-right: 2%; margin-top: 1%">
<a data-toggle="collapse" ng-click="getEntitlement(ent.attributename)"
data-target="#collapse{{$index}}"> {{ent.attributename}}</a>
</div>
<DIV id="collapse{{$index}}" class="panel-collapse collapse">
<div ng-repeat="ep in EndpointList"
<div style="height: 20px; margin-left: 2%; margin-top: 1%;">{{ep.endpointname}}</div>
</div>
</DIV>
</DIV>
</DIV>
` say I have 3 links,when i expand the each link after collapsing the previous one, It is working fine. But the problem i am facing is, if i expand the second link without collapsing the first one, the value of the second link is overriding the value of the first link.
Please help me to resolve this issue.
Java script file has the following function:
$scope.getEntitlement = function(selecteEntitlement)
{
var finalList=[];
$scope.EndpointList="";
$scope.entitlementInfo.forEach(function(entitlement)
{
if(entitlement.attributename == selecteEntitlement)
{
finalList.push({endpointname: entitlement.endpointname
});
}
});
$scope.EndpointList = finalList;
};
Your problem is using the same variable $scope.EndpointList for every expandable click. The solution is, you have create separate EndpointList for each ent (element from EntitlementList), then you could use
ng-repeat="ep in ent.EndpointList"

embedded stylesheet with angular-defined values

I am repurposing the HTML/CSS for this survey widget.
The CSS is built for a fixed number (5) of options (radio buttons), but I can dynamicize it using ng-repeat so that it can hold anywhere from 3 to 9 options, as the data requires.
The CSS needs to be dynamic as well to account for a variable number of options.
<div class="wrap">
<div class="widget-wrapper likert-scale-widget" action="">
<ul class='likert1'>
<li ng-repeat="option in item.response.options>
<input type="radio" name="likert" ng-value="option.value">
<label>{{option.label}}</label>
</li>
</ul>
</div>
</div>
The CSS makes extensive use of pseudo-classes:
div.likert-scale-widget .likert1:before {
top: 11px;
left: 9.5%;
display: block;
width: 78%;
}
You can't put pseudo-classes directly inline, so I can't do this:
<div class="likert-scale-widget">
<div class="likert1" style="width:78%">
So what I have to do is embed my styles in a element at the top of the page. Then I can target it with Angular:
<style>
div.likert-scale-widget .likert1:before {
top: 11px;
left: {{ 12 - item.response.options.length*1.1 }}%;
display: block;
width: {{ 74 + item.response.options.length }}%;
}
</style>
Problem is, this is very non-standard markup. My GUI hates the multiple use of parentheses.
Is there a better way of doing this?
You can use ng-style. Looks really hackish, but if your styles are dynamic towards the content, then I guess its justifiable.
Declare a variable to get the entire styles in a key value format.
$scope.likerStyle = {
'top': '11px';
'left': (12 - item.response.options.length*1.1) + '%'; // '+' automatically stringify this
'display': 'block';
'width': (74 + item.response.options.length) +'%';
};
Then at your markup, use this:
<div class="wrap">
<div class="widget-wrapper likert-scale-widget" action="">
<ul class='likert1' ng-style='likerStyle'>
<li ng-repeat="option in item.response.options>
<input type="radio" name="likert" ng-value="option.value">
<label>{{option.label}}</label>
</li>
</ul>
</div>

ng-click first apply class, then execute function

I have a shopping cart (a rootScope array) which gets turned into a list of items in it, including a button to delete that item from the cart array (the red X).
I don't have enough reputation to add an image, so here's a link to what it looks like
What I want to have happen is when I click one of the red X buttons, the item first does an animation(some sort of fade out), and then the actual cart has the item spliced from it. Using ng-click I am able to either do one or the other, but not both. When both is applied the animation doesn't trigger because it doesn't have time to. Is there a way to wait for the animation to finish, then perform the function?
(the animation executed by applying a class to the div on ng-click, so possibly a watch for class change?)
Here's my code. The code won't work in the snippet but you can see my functions and html.
$scope.removeFromCart = function(removedGame) {
index = $rootScope.cartArray.indexOf(removedGame);
$rootScope.cartArray.splice(index, 1);
};
$(".disappear").hasClass('fadeOutRight')(function(){
$scope.removeFromCart(cartArray[0]) ;
});
.cartGameDiv {
height: 140px;
width: auto;
}
<div ng-repeat = "newGame in cartArray" ng-class="disappear">
<div>
<div class="col-sm-11 col-lg-11 col-md-11 cartGameDiv">
<div class="thumbnail">
<div class="pull-left">
<img style="height: 100px; width: 213px; padding: 5px; margin-top: 5px" src="{{newGame.thumbnail}}" alt="">
<div id="ratingDiv" style="margin-left: 8px; margin-right: 8px; margin-bottom: 5px;">
<div style="display: inline-block" ng-bind-html="getTrustedHtml(newGame)"></div>
<p class="pull-right" style="color: #d17581">{{newGame.numberReviews}} reviews</p>
</div>
</div>
<div class="caption">
<h4 style="margin-top: 0" class="pull-right">{{newGame.price}}</h4>
<h4 style="margin-top: 0"><a class="categoryGameName" href="#details/{{myGamesList.indexOf(newGame)}}">{{newGame.name | removeSubName}}</a>
</h4>
<p>{{newGame.description.substring(0,290) + '...'}}</p>
</div>
</div>
</div>
</div>
<div class="col-sm-1 col-lg-1 col-md-1 cartGameDiv">
<img style="margin-bottom: 10px; margin-top: 10px;" src="images/glyphIconCheckmark.png" alt=""/>
<img ng-click="disappear='animated fadeOutRight'; removeFromCart(newGame)" style="margin-bottom: 10px" src="images/glyphIconRemoveGame.png" alt=""/>
<img src="images/glyphIconLike.png" alt=""/>
</div>
</div>
If you have any idea how to delay the function call until after the animation I'd really appreciate it! Thanks!
This is very simple to do using ngAnimate. Add the ngAnimate script to your page (you can get this from numerous CDNs), include ngAnimate as a dependency to your module and then just add some simple CSS.
.ng-leave{
-webkit-animation: fadeOutRight 1s;
-moz-animation: fadeOutRight 1s;
-o-animation: fadeOutRight 1s;
animation: fadeOutRight 1s;
}
In your example, you need not do any work applying the class yourself, ngAnimate will do it for you.
Here is a Plunker demonstrating how you would do it.

Insert something between elements generated with ng-repeat

What would be the best way, to append an element in between elements generated using ng-repeat?
For example:
<div class="block" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]">{{position+1}}</div>
I would like to put a <br> after every 4th element. My guess would be to create a directive with the link.post. Tell me if I'm on the good track.
Thank you
jsFiddle: http://jsfiddle.net/uPMZU/
I'm not entirely sure what you're trying to achieve with the <br> but if your are trying to stack them in groups of four then you can do something using the $index variable from ng-repeat and a class change.
JSFiddle with this: http://jsfiddle.net/y44Cb/13/
HTML
<div ng-class="{block: ($index +1) % 4}" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]">
<div class="red-block">{{position+1}}</div>
</div>
CSS
div.red-block {
display: inline-block;
border: 1px solid red;
width: 50px;
height: 50px;
}
div.block {
float: left;
}
You could use ng-repeat-start and ng-repeat-end and then check whether you want to render the break in a function.
<div class="block" ng-repeat-start="position in [1,2,3,4,5,6,7,8,9,10]">
<div class="red-block">{{position+1}}</div>
</div>
with
<br ng-if="includeBreak(position)" ng-repeat-end>
or
<p ng-if="includeBreak(position)" ng-repeat-end></p>
You can use an ng-switch to do what you need
<div class="block" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]" data-ng-switch on="($index + 1) % 4 == 0 && $index > 0">
{{position+1}}
<br data-ng-switch-when="true">
</div>
jsfiddle: http://jsfiddle.net/7qrne/ if you inspect the "5" div you'll see it has the same with the "9" div, but none of the others.

Vertical inline-block?

Currently I have something like this. The "Page" and "Row" elements are created dynamically using javascript.
The problem rises when there are multiple Pages, and a Row in the Page 1 is deleted, for example. The empty space should be filled by the element that is below, if the empty space is at the end of the page, then the first element of the next page should fill the empty space, and so on. At the end it should look like this.
I can solve this rearranging/recreating the entire PageCont.
Is there a way I can achieve this using pure CSS? So the rearranging would be handled by the rendering engine of the browser.
Something like this inline-block but with vertical direction.
Any help is highly apreciated.
​HTML:
<div class="PageCont">
<div class="Page">
<div class="Row">1</div>
<div class="Row">2</div>
<div class="Row">3</div>
<div class="Row">4</div>
</div>
<div class="Page">
<div class="Row">5</div>
<div class="Row">6</div>
<div class="Row">7</div>
<div class="Row">8</div>
</div>
<div class="Page">
<div class="Row">9</div>
</div>
</div>​
CSS:
.PageCont
{
height: 300px;
width: 350px;
border:2px solid red
}
.Page
{
float:left;
margin-left:10px;
}
.Row
{
height:50px;
width:50px;
background-color:blue;
color:white;
margin-top:10px;
}
​
The operation could be successfully performed trivially if it included horizontal wrapping, with plain simple CSS. However since this case involves vertical wrapping javascript be necessary with your current implementation. If you were to use columns you wouldn't need the javascript and CSS is all that's needed.
Here is a fiddle where I've implemented it http://jsfiddle.net/eQvaZ/
The HTML is as follows:
<body>
<div class="pageCont">
<div class="Row">C1</div>
<div class="Row">C2</div>
<div class="Row" id="to-remove">C3</div>
<div class="Row">C4</div>
<div class="Row">C5</div>
<div class="Row">C6</div>
<div class="Row">C7</div>
</div>
<div>Removing C3 in 5 seconds...</div>
</body>
The CSS:
.pageCont{
column-count:2;
column-rule:0px;
-webkit-column-count: 2;
-webkit-column-rule: 0px;
-moz-column-count: 2;
-moz-column-rule: 0px;
padding:10px;
height: 250px;
width: 200px;
border:2px solid red
}
.Row {
height:50px;
width:50px;
background-color:blue;
color:white;
margin-bottom:10px;
}
The bit of JavaScript to remove an item:
setTimeout( function(){
var to_remove = document.getElementById('to-remove');
to_remove.parentNode.removeChild(to_remove);
}, 5000);
Let me know if you have any questions regarding this implementation.

Resources