Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#1 2013-06-25 14:14:29

aslsw66
Member
From: Canberra, Australia
Registered: 2004-08-04
Posts: 342
Website

Simulate a FOR...EACH loop

I’ve used Twitter’s Bootstrap to rebuild my personal site. One of the elements I want to use is the image carousel to feature particular photos on the homepage, building it dynamically from images in the category of “carousel”. This means that I don’t know the number of images to use might change each time.

Here’s the demo coding for the carousel:

   <div id="myCarousel" class="carousel slide">
    <ol class="carousel-indicators">
    <!-- Carousel indicators -->
      <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
      <li data-target="#myCarousel" data-slide-to="1"></li>
      <li data-target="#myCarousel" data-slide-to="2"></li>
    </ol>
    <!-- Carousel items -->
    <div class="carousel-inner">
      <div class="active item"><img src="..."></div>
      <div class="item"><img src="..."></div>
      <div class="item"><img src="..."></div>
    </div>
    <!-- Carousel nav -->
    <a class="carousel-control left" href="#myCarousel" data-slide="prev">&lsaquo;</a>
    <a class="carousel-control right" href="#myCarousel" data-slide="next">&rsaquo;</a>
    </div>
  </div>

You can see that there are two places where loops are required – firstly, to create the correct number of carousel indicators and the secondly to display each individual image ‘item’.

The second loop to build the ‘slide’ for each image is easier using the available <txp:images> tag or <txp:smd_query> but I’m having trouble figuring out how to do the first one:

  • I can find out the total number of images in the correct category using <typ:smd_query>,
  • I can manipulate a counter using <txp:adi_calc>,
  • but I don’t know how to stop the counter when it reaches the maximum. It feels like a job for <txp:smd_each>, but I think <txp:smd_each> needs the full set of variables before processing (which I don’t know how to do!).

Note that this has to be two loops, because they reside in completely separate blocks.

If was going to use pseudo-code, it would be something like:

$n=[number of images]
$counter=1
while $counter <= $n
  [output my code]
  $counter++
endwhile

It feels like the answer is close, but each time I think I have the solution it just slips away and I’m stuck in a dead-end.

Offline

#2 2013-06-25 14:30:44

mrdale
Member
From: Walla Walla
Registered: 2004-11-19
Posts: 2,215
Website

Re: Simulate a FOR...EACH loop

etc_query is really good at this kind of thing (obtaining datasets and reformatting them).

Offline

#3 2013-06-25 14:49:35

etc
Developer
Registered: 2010-11-11
Posts: 5,396
Website GitHub

Re: Simulate a FOR...EACH loop

mrdale wrote:

etc_query is really good at this kind of thing (obtaining datasets and reformatting them).

I agree. :) First extract your images using the format you need, and store them in some <txp:variable name="images" />:

<txp:variable name="images">
<txp:images wraptag="div" break="" class="carousel-inner">
<div class="item"><img src="<txp:image_url />"></div>
</txp:images>
</txp:variable>

Now pass it to etc_query to construct the first block:

   <div id="myCarousel" class="carousel slide">
    <!-- Carousel indicators -->
    <txp:etc_query data='<txp:variable name="images" />' query="div/div" wraptag="ol" class="carousel-indicators">
      <li data-target="#myCarousel" data-slide-to="{#ind}"></li>
    </txp:etc_query>
    <!-- Carousel items -->
    <txp:variable name="images" />
    <!-- Carousel nav -->
    <a class="carousel-control left" href="#myCarousel" data-slide="prev">&lsaquo;</a>
    <a class="carousel-control right" href="#myCarousel" data-slide="next">&rsaquo;</a>
    </div>
  </div>

But I guess your carousel will use js, so jQuery might suit your needs better.

Offline

#4 2013-06-25 15:08:47

aslsw66
Member
From: Canberra, Australia
Registered: 2004-08-04
Posts: 342
Website

Re: Simulate a FOR...EACH loop

OK, I’ve just been reading through the etc_query documentation – it look very flexible, but it also looks like I have a steep learning curve ahead of me! But I like the idea of just getting all of my data, including the output HTML, into a single variable once (I was thinking along the lines of multiple passes). I didn’t realise that we could traverse a single Textpattern variable like that and just pull out the interesting bits.

I’m not much of a programmer any more, but I’m happy to try out the example and test it out. The total number of images will be limited (say, no more than 4) but I want to pull out 4 random images out of the total.

Thanks for your help, this gives me a great starting point to start testing later this afternoon.

Offline

#5 2013-06-25 16:14:29

etc
Developer
Registered: 2010-11-11
Posts: 5,396
Website GitHub

Re: Simulate a FOR...EACH loop

Variables are very cute. Actually, there is an “almost” core solution, you need a plugin only to increment some <txp:variable name="counter" />. I use <txp:etc_query data="{?counter|0|+1}" /> here, but I guess one can go with adi_calc:

<txp:variable name="images">
<txp:images wraptag="div" break="" class="carousel-inner">
	<div class="item"><img src="<txp:image_url />"></div>
	<!-- increment counter variable by 1 or initialize it if not defined -->
	<txp:etc_query name="counter" data="{?counter|0|+1}" globals="variable" />
	<txp:variable name="indicators">
		<txp:variable name="indicators" />
		<li data-target="#myCarousel" data-slide-to='<txp:variable name="counter" />'></li>
	</txp:variable>
</txp:images>
</txp:variable>

<div id="myCarousel" class="carousel slide">
	<ol class="carousel-indicators">
		<!-- Carousel indicators -->
		<txp:variable name="indicators" />
	</ol>
	<!-- Carousel items -->
	<txp:variable name="images" />
	<!-- Carousel nav -->
	<a class="carousel-control left" href="#myCarousel" data-slide="prev">&lsaquo;</a>
	<a class="carousel-control right" href="#myCarousel" data-slide="next">&rsaquo;</a>
</div>

Offline

#6 2013-06-25 17:26:36

mrdale
Member
From: Walla Walla
Registered: 2004-11-19
Posts: 2,215
Website

Re: Simulate a FOR...EACH loop

etc wrote: {#ind}

dumbest question yet

…is there an exhaustive list and explanation of the stuff you can put inside the curly braces?

for example, I know what the # does but what does ind do? does it echo “ind” or does it have some special reseved function?

Last edited by mrdale (2013-06-25 17:50:48)

Offline

#7 2013-06-25 17:36:32

etc
Developer
Registered: 2010-11-11
Posts: 5,396
Website GitHub

Re: Simulate a FOR...EACH loop

{#ind} is the current row number, starting with 0. I try to maintain the help up to date, but not always succeed, sorry. There is some additional info here and there.

Offline

#8 2013-06-25 17:57:44

mrdale
Member
From: Walla Walla
Registered: 2004-11-19
Posts: 2,215
Website

Re: Simulate a FOR...EACH loop

Oh, duh. thanks

Last edited by mrdale (2013-06-25 17:57:59)

Offline

#9 2013-07-01 21:50:13

aslsw66
Member
From: Canberra, Australia
Registered: 2004-08-04
Posts: 342
Website

Re: Simulate a FOR...EACH loop

Thanks for your help- Oleg’s solution worked perfectly (well, so far – only 2 images). The only modification I had to make was to test for the first image, so that it could get the “active” class. I used <txp:smd_if> for this purpose.

If you’re interested in what it looks like, my website is here. Note that the Twitter feed broke, so I need to incorporate the suggested changes to <txp:arc_twitter>. And actually add some fresh content. And fix the contact form. And a few other things …

Offline

#10 2013-07-02 21:28:08

etc
Developer
Registered: 2010-11-11
Posts: 5,396
Website GitHub

Re: Simulate a FOR...EACH loop

aslsw66 wrote:

The only modification I had to make was to test for the first image, so that it could get the “active” class. I used <txp:smd_if> for this purpose.

I guess you could use <txp:if_variable name="counter" value="0" /> to detect the first image.

That makes me think that some kind of <txp:counter /> and <txp:if_counter /> tags could be useful inside loop structures, and would partially replace <txp:if_first_... /> tags.

Offline

#11 2013-07-02 21:46:41

aslsw66
Member
From: Canberra, Australia
Registered: 2004-08-04
Posts: 342
Website

Re: Simulate a FOR...EACH loop

Stef has seduced me in to believing he has the answer for everything. It’s hard to remmeber that Textpattern can actually function without one of his plugins.

Offline

#12 2013-07-03 14:19:36

etc
Developer
Registered: 2010-11-11
Posts: 5,396
Website GitHub

Re: Simulate a FOR...EACH loop

aslsw66 wrote:

Note that the Twitter feed broke, so I need to incorporate the suggested changes to <txp:arc_twitter>.

Want them? Just add screen_name=your_screen_name to this link.

Offline

Board footer

Powered by FluxBB