How to get the item before the last iteration in the loop of a Smarty array - smarty

Hello smart(y) Girls and Guys!
Unfortunately I can't find an answer and of course I am new to Smarty.... Hope you can helo me out!
I am looking for the item before the last item of a smarty foreach loop. So e.g if my array has 8 iterations i need the 7th iteration, if there are 3 iterations, I need the 2nd ... and so on.
How can I get it? I can get the .last one, but how to get the one before?

There are "{foreach} properties": #index, #iteration, #first, #last, #show, #total.
Example for your case:
{foreach $array as $a}
{if $a#iteration == $a#total-1}
last-1 value is: $a
{/if}
{/foreach}

Related

Smarty: How to do X when foreach hits half of total

In smarty [v2 to my knowledge] I can not figure i can present some data in a foreach loop when it is halfway through. Ie. separate the first half of array and the second half of the array into two different div elements.
This is where I currently am, and is the logic to what I am trying to accomplish..
<div>
{foreach from=$feature.variants item="var" name="var"}
{if $smarty.foreach.var.iteration == ($smarty.foreach.var.total % 2)}
</div>
<div class="ty-product-feature__value">
{/if}
{$var.variant}
{/foreach}
</div>
I have everything correct except line 2. I cannot figure out how to properly set it to activate when the current loop iteration equals half of the total amount of times the foreach will loop [meaning regardless of the items it the array, it will put half in one div element and the other half in a second div element.
Also, this is less of a priority but what happens when an uneven array total is present and it can't divided equally in half?
Thank you so much in advance! This is beyond my expertise and am sure there is someone with a better understanding of this than me.
% is for modulus, so the condition is triggering every two items, and that's not what you want. Instead try to check if the current iteration is in the middle of the total number of items in the array. Use ceil so the result of the division is always an integer rounded up:
{assign var="loop_middle" value=$feature.variants|#count/2}
{foreach from=$feature.variants item="var" name="var"}
{$var.variant}
{if $smarty.foreach.var.iteration == $loop_middle|ceil}
</div>
<div class="ty-product-feature__value">
{/if}
{/foreach}
So i.e. if you have 11 items, you will end up with two divs, one with 6 items an another with 5

Scraping tracklist

I'm trying to scrape a tracklist from a website. My relevant code is:
page.css('ol').each do |line|
subarray = line.text.strip.split(" - ")
end
This makes the array take the first artist into the first index (as I want), but adds the track and the artist of track two into the second index like this:
subarray[0] = Rick Wilhite
subarray[1] = Magic Water [Still Music]
Edward
subarray[2] = Into A Better Future [Giegling]
Kassem Mosse
subarray[3] = Zolarem [Mikrodisko Recordings]
After Hours
I included the nested tag so my code reads:
page.css('ol li').each do |line|
subarray = line.text.strip.split(" - ")
end
but this only seems to leave subarray[0] displaying "Klara Lewis" and subarray[1] displaying "Shine [Editions Mego]", which is the last track on the tracklist. All other index values are blank.
A further complication is that I would like to remove the record label from what will end up being the track value. I believe the correct regular expression is \[[\d\D]*?\], but I'm under the impression that this needs to be applied before the data goes into the array to avoid complications involved in iterating over arrays. I tried passing it as a second delimiter to split (along with ' - ') which didn't work, and I also attempted to test it by changing my code to:
page.css('ol').each do |line|
subarray = line.text.strip.split("\[[\d\D]*?\]")
end
but that also appears not to work. Can anyone help me on this or give me the right pointers?
Here's what's happening:
page.css('ol') gives you the entire <ol> with every one of the <li> tags:
<ol>
<li>Rick Wilhite...</li>
<li>Edward...</li>
...
<li>Klara Lewis...</li>
</ol>
When that one big chunk enters the .each loop, you're only running through the loop once. So when you apply the .split(" - ") method, subarray will be filled once with all the text separated by -.
On the other hand, page.css('ol li') gives you each individual <li>, like this:
<li>Rick Wilhite...</li>
<li>Edward...</li>
...
<li>Klara Lewis...</li>
This time, you're running through the loop 17 times, once for each <li> tag. The first time through, .split(" - ") is applied to the text and stored in the subarray variable. The problem is that the next time through the loop, subarray is overwritten with the split text of the second <li>. So after the final time through, the only contents of the subarray variable is the split text of the final <li>: "Klara Lewis" and "Shine [Editions Mego]".
I think you've gotten the general idea of how to scrape from a website, but I recommend building your script more incrementally so you understand exactly what you're doing in each step. For example, use puts to check what page.css('ol') gives you and how it differs from page.css('ol li'). What happens when it goes through a loop? What do you get when you apply .split()? Building more slowly and exploring around to make sure you understand what you're doing will help you avoid hitting dead ends. Hope that helps!

Get every element after the third on smarty

hello I want to apply an specific class to every 3rd element and the next one getting the third element was easy I used
{if $smarty.foreach.products.index % 3}omega{else}
but getting the next one its being tricky, i tried with
{if $smarty.foreach.products.index % 3+1}omega{else}
but doesnt work, do you know whats the correct way of writing?
I cannot try it right now, but it should be
{if ($smarty.foreach.products.index-1) % 3 == 0}omega{else}
you should get omega when index = 4, 7, 10....
use iteration and index:
{if $smarty.foreach.products.iteration is div by 3 or $smarty.foreach.products.index is div by 3}omega{/if}
iteration starts counting at 1 (1,2,3,...), so the third element will get the class and as index starts counting at 0 (0,1,2,3,...), the 4th element will also get the class
read more about foreach in smarty at http://www.smarty.net/docsv2/en/language.function.foreach.tpl
Use .iteration
iteration contains the current loop iteration and always starts at
one, unlike index. It is incremented by one on each iteration.
Smarty 3
{foreach $myArray as $foo}
{if $foo#iteration % 3 == 0}
Smarty 2
{foreach from=$myArray item=i name=foo}
{if $smarty.foreach.foo.iteration % 3 == 0}

Smarty variable in array index

Have months array $months('January', 'February', 'May')
and want show this month in loop
{for $foo=1 to 3}
{$months[$foo]}
{/for}
I get white page, what is wrong with my code ?
First, make sure that you're defining the array properly:
$months = array('January', 'February', 'May');
Then, make sure the indices are correct (in PHP array indices start from 0):
{for $foo=0 to 2}
{$months[$foo]}
{/for}

comparing a number with an array item in smarty

This is what I would like to do:
I have assigned the following items:
$smarty->assign('seats', $aantalStoeltjes);
$smarty->assign('taken', $bezetArray);
"seats" is the number of seats available. This is an array with only one item. The number 150 in this case but is dynamic.
"taken" is the seats that are already taken and should not be displayed. This is also an array with several items in it like movietitle, play day, etc. The taken seats are assigned to "seatnumber".
What I need is to let smarty to add foo 150 times (in this case). If the seat's number is equal to the taken number the foo should not be added.
So to sum it up.
foo should be added 150 times in this case, but if the number is equal to one of the seatnumbers in the "taken" array it should be skipped.
This is what I tried:
{section start=1 loop=$seats+1 step=1}
{foreach from=$taken item=tolate}
{if $smarty.section.seats.index != $tolate.seatnumber}
<p>{$tolate.seatnumber}</p>
<p>{$smarty.section.seats.index}</p>
{/if}
{/foreach}
{/section}
but this doesn't work correctly. Can anyone help me?
It would be much simple if you would use this:
{foreach from=$taken item=tolate}
{if $tolate.seatnumber != $seats}
<p>{$tolate.seatnumber}</p>
<p>{$seats}</p>
{/if}
{/foreach}

Resources