Add classes within ngFor loop - javascript

How do I add different classes for the inner elements in an ngFor loop in Angular 4? Say, I have a snippet:
<div *ngFor="let article of articles">
<div>
<h3>{{article.name}}</h3>
<p>{{article.body}}</p>
</div>
</div>
So I have 2 questions: how do I add different classes to the h3 elements in every generated article based on their order (first, second, third) and how do I add classes to the h3 elements based on odd-even order?

You can get the index, odd, and even of the current iteration in the ngForOf, combine that with ngClass and you can set the class.
<div *ngFor="let article of articles; index as i; even as isEven; odd as isOdd">
<div id="article">
<h3 [ngClass]="{'odd': isOdd, 'even': isEven}">{{article.name}}</h3>
<p>{{article.body}}</p>
</div>
</div>
You do not mention how you want to use the index/position so there is no code for that. I am sure you can figure that part out though based on the sample code above and documentation.
As #Paco0 also pointed out maybe you meant id="article" to be id="{{article.id}}" or something similar?

Related

Dynamically creating jQuery UI sliders: I want to set unique ids for both slider handles to give them custom text

I'm dynamically creating jQuery UI sliders, using the following code in a forEach loop:
// Sets an id for the slider handles, gives them a custom class (makes them appear as circles, centers them)
$("#slideRange" + i).find(".ui-slider-handle").attr("id","slideHandle" + i).addClass("customSliderHandle");
// These two lines set the times below the slider handles.
$("#timeSlider" + i).find(".slideStartLabel").text(startTime);
$("#timeSlider" + i).find(".slideEndLabel").text(endTime);
This successfully makes the following slider, with variable times, for every iteration:
What I'd like to do, instead of showing the times below the circular handles, is have the times appear in the middle of the handles. The end result would look like this (photoshopped):
The times will then update, according to the slider values, within the "slide" event callback.
My question is: how do I assign unique id's to the two slider handles, so that I can then set their text independently in the "slide" callback? The code I wrote above gives both handles the same id. Using this id to set text to a handle will only apply to the first handle, leaving me no way to change the text of the second. Using find(), get(), or just $(".ui-slider-handle") are all ways of getting an array of the slider handles, but when I try attr("id","uniqueId") on one of the elements of that array, I get "(...).method(...) is not a method".
Or is assigning unique id's the wrong approach, here? Is there a jQuery or vanilla Js way of setting attributes of one element at a time, when searching by class and getting potentially multiple results?
Also, for context: I'm using find() because I'm using clone() on a markup shell, then appending it to a central div. Here's the shell:
<!-- This hidden div will be cloned, customized, and appended onto .modal-body -->
<div id="timeslotShell" class="timeslot row" style="display:none">
<div class="container-fluid slotContents" id="slotContents">
<span class="col-md-4"> Listing <div class="slotNumber listNum">*Listing No.*</div>: From <div class="slotNumber startNumber slotStartShell"> *Start Time* </div> until
<div class="slotNumber endNumber slotEndShell"> *End Time* </div> </span>
<div class="col-md-8">
<button type="button" class="btn btn-md btn-info slotButton">
Choose A Time From Within These Hours
</button>
</div>
<div id="timeSliderShell" class="collapse timeSlider">
<br><br>
<div id="slider-range" class="slideRange row"></div>
<div id="slideLabels" class="slideLabels slideRange row">
<div class="slideStartLabel"></div><div class="slideEndLabel"></div>
</div>
</div>
</div>
<br><br>
</div>
Cool -- as luck with have it, I found the answer shortly after posting this. Check this post if you're dealing with a similar issue:
Slider Value Display with jQuery UI - 2 handles
All that's needed, in the .find() calls, is
.find(".ui-slider-handle:first").text(value1);
for the first handle and then
.find(".ui-slider-handle:last").text(value2);
for the second.

AngularJS: open and close DOM element during different cycles of ng-repeat

I wonder if it is possible to open DOM element during first cycle of ng-repeat and close it during the second. Let's talk about some list of element, and I want to output it by 2 (or may be 3, 4... it does not matter) in a row. So result html will be like this:
<div class="row"> <!-- add this line during 1sr cycle -->
<div class="element">...element1...</div>
<div class="element">...element2...</div>
</div> <!-- add this line during 2nd cycle -->
<div class="row"> <!-- add this line during 3rd cycle -->
<div class="element">...element3...</div>
<div class="element">...element4...</div>
</div><!-- add this line during 4th cycle -->
The main problem that ng-repeat does not allows me to put line <div class="row"> on first cycle and put closing </div> on second cycle. ng-repeat add both of them during every cycle. Is it possible to find some workaround for this case?
It's not possible with ng-repeat. You have to either prepare the data structure in your controller (multi-dimensional array) or write a custom directive that would take and additional parameter of how many elements of the array take for the current iteration.
UPD: You can use lodash' chunk function to split the array into smaller arrays https://lodash.com/docs#chunk
As you said, you can't output only half an element (e.g. the opening tag without the closing tag) in one repeat cycle.
You can however do different things in one cycle based on the $index property, like showing or hiding a specific element in the first cycle ($index: 0).
Alternatively, have a look at ng-repeat-start and ng-repeat-end to output more than one element in a cycle. More info: https://docs.angularjs.org/api/ng/directive/ngRepeat
I have found simple solution out of the box in angularJs:
<div class="row" ng-repeat="element in elements" ng-if="$index%2==0">
<div class="element" ng-repeat="element in elements|limitTo:2:$index">...</div>
</div>
It will output 2 elements in a row, if you need more, you should adjust ng-if and limitTo argument.

Setting a variable in parent div and using it in children in angular

I'm new to AngularJS. I'm developing a page with a couple of similar blocks but I don't really want to use ng-repeat for those. The thing is, in their ng-click, ng-class and other directives I need to use some variable identifying the block. Is there a way to set it once in parent div and then use in children? Something like this:
<div ng-var="Potatoes">
<button ng-click="buy($parent.var)">Buy</button>
<span>This is a {{$parent.var}}</span>
<img ng-class="{{$parent.var}}">
</div>
<div ng-var="Tomatoes">
<button ng-click="buy($parent.var)">Buy</button>
<span>This is a {{$parent.var}}</span>
<img ng-class="{{$parent.var}}">
</div>
I would use ng-repeat over a specifically crafted object but in this case I have to manually position some other things that I omitted in the code above so ng-repeat is not an option, unfortunately.
You can still use 'ng-repeat' then use of '$index' can differentiate each loop.

Angular JS - How to add extra DIV in ng-repeat

I have an array a=[1,2,3,4,5,6].
Using ng-repeat on this array, I am creating 6 divs.
Please refer to this plunker
Is there any way to add one more div after each row. So after 3 divs I want to add one extra div.
I looked into this example. but they are creating a child div. is it possible to create a sibling div in ng-repeat
Let's try ng-repeat-start & ng-repeat-end.
<div class="example-animate-container">
<div class="square" ng-repeat-start="friend in a">
{{$index}}
</div>
<div ng-if="$index % 3 == 2" ng-repeat-end>
extra div
</div>
</div>
Please note that ng-repeat-start directive is included since angular 1.2.1.
plnkr demo
ng-repeat: repeat a series of elements of "one" parent element
<!--====repeater range=====-->
<Any ng-repeat="friend in friends">
</Any>
<!--====end of repeater range=====-->
ng-repeat-start & ng-repeat-end: using ng-repeat-start and ng-repeat-end to define the start point and end point of extended repeater range
<!--====repeater range start from here=====-->
<Any ng-repeat="friend in friends" ng-repeat-start>
{{friend.name}}
</Any><!-- ng-repeat element is not the end point of repeating range anymore-->
<!--Still in the repeater range-->
<h1>{{friend.name}}</h1>
<!--HTML tag with "ng-repeat-end" directive define the end point of range -->
<footer ng-repeat-end>
</footer>
<!--====end of repeater range=====-->
The ng-repeat-start and ng-repeat-end syntax was introduced for this exact purpose. See the documentation http://docs.angularjs.org/api/ng/directive/ngRepeat
So you'll do something like:
<div ng-init="a = [1,2,3,4,5,6]">
<div class="example-animate-container">
<div class="square" ng-repeat-start="friend in a">
{{$index}}
</div>
<div ng-repeat-end>Footer</div>
</div>
You can use a empty div as a container for your repeat. And then only render the child element's as squares (or what ever you want). This way, your extra div will be a sibling and not a child.
See my example: http://plnkr.co/edit/xnPHbwIuSQ3TOKFgrMLS?p=preview
take a look at this plunker here, could it be your solution? i don't understand really well your problem because i think it's better if instance your array in an external js file, but other than that take a look here plunker

Positioning issue in ExpressionEngine cms

I have a positioning issue with my in expression engine. click Here On the following link I am looping elements with <div id="services-container"> I have noticed it loops fine on the first row however begins to misalign on the second row. I have made attempts to use the switch="" tag to create an individual class for each loop, see below:
{exp:channel:entries channel="services" dynamic="no" sort="asc|desc"}
<div id="services-container" class="{switch='1|2|3|4|5|6'}">
<div class="service-content">
<img src="{service_image}" alt="banner" alt="{alt}" class="service-banner">
<p>{service_head_line}</p>
{service_listed_items}
<ul class="service-credentials">
<li>{service_list_1}</li>
<li>{service_list_2}</li>
<li>{service_list_3}</li>
</ul>
<ul class="service-credentials">
<li>{service_list_4}</li>
<li>{service_list_5}</li>
<li>{service_list_6}</li>
</ul>
View related projects ยป
{/service_listed_items}
</div><!--service-content-->
</div><!--SERVICES CONTAINER-->
{/exp:channel:entries}
When i try to class these classes out in my style sheet nothing is happening. Does anyone know what i am doing wrong?
This involves ExpressionEngine but also css. Basically you are trying to create a grid with 3 items in each row, correct ?
Each of these "row" has to adopt a float containment strategy, since it only contains 3 floated items. The way I would go about it using the switch parameter:
{exp:channel:entries channel="services" dynamic="no" orderby="date" sort="asc"}
{if "{switch='one|two|three'}" == "one"}<div class="row">{/if}
<div class="item">
...code...
</div>
{if "{switch='one|two|three'}" == "three" || count == total_results}</div>{/if}
{/exp:channel:entries}
That code would include a div with a class of row every three items in that loop.
Then, if your items are floated, your rows must have some sort of float clearing strategy to contain them like overflow:hidden; or a clearfix method.

Categories