TYPO3 fluid array key increment by 1 - typo3

In fluid template I am displaying items list
<f:for each="{myItems}" as="myItem" key="key">
{key}. myItem.name
</f:for>
Here I need to display serial number for each item.
for example,
1. myitem one
2. myitem two
etc.
But in my case I used {key} for serial number. But its starting from 0.
0. myitem one
1. myitem two
So how to increment key by 1 for displaying only ?
Thanks.

You can use iteration="" property and then cycle. It starts from 1 instead of 0.
<f:for each="{myItems}" as="myItem" iteration="itemIterator">
{itemIterator.cycle}. myItem.name
</f:for>
tip: f:for iterator contains other useful properties, like isFirst, isOdd etc.
Check the wiki for more datails

In Fluid standalone and TYPO3v8 and above:
<f:for each="{myItems}" as="myItem" key="key">
{key + 1}. myItem.name
</f:for>
The key (no pun intended) is the MathExpressionNode and any implementation of Fluid which intentionally disables this implementation will not support this expression - in those cases, iterator.cycle is your friend.

Related

TYPO3 9 and Flux: Adding an element / section / container multiple times

I'm using TYPO3 9.5.26 and Flux 9.4.2 and I would like to create a calendar-element with exactly five elements/days. Each day needs some input fields. It would look something like this:
Calendar:
Day 1: Offer ID, Image
Day 2: Offer ID, Image
Day 3: ...
Considering DRY, I would like to use some kind of for-loop, but this doesn't work. What I tried:
<f:section name="Configuration">
...
<f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo" key="number">
<flux:field.multiRelation label="Angebot Tag 1" name="offerDay1" table="tx_data_domain_model_offer">
</flux:field.multiRelation>
</f:for>
If I enter five of the multiRelation-fields, it works as expected but as these subelements will get more input fields the code would get bloated.
I also tried using a flux section but it seems like there is no option of limiting the number of elements to exactly five.
Thanks to j4k3's last comment on my question I found out what I was doing wrong: I was trying to apply multiple fields with the same name which isn't allowed. This code using the 'key' works (could also use iteration):
<f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo" key="number">
<flux:field.multiRelation label="Angebot Tag {number}" name="offerDay{number}" table="tx_data_domain_model_offer">
</flux:field.multiRelation>
</f:for>

TYPO3 Fluid Templates variables

I'm trying to set a variable in a Fluid template.
I try to divide something by 2 :
<f:variable name="hmc">{menu->f:count()} / 2</f:variable>
It does not work because I get a string instead of a numeric result.
I think you can't do it in a one-liner. You have to count first and then do the math.
<f:variable name="count">{menu -> f:count()}</f:variable>
<f:variable name="hmc">{count / 2}</f:variable>

Add additional source to Image for further actions

im trying to add an additional source to the dce-image for further actions e.g. an alternate source to perform some JavaScript actions.
The wanted output should look like this:
<img src="path/to/foo.png" data-altsrc="path/to/bar.png">
The problem is the dce i'm using - its iterating through the "images" like this:
<f:for each="{dce:fal(field:'image', contentObject:contentObject)}" as="fileReference">
<f:image src="{fileReference.uid}" treatIdAsReference="1" />
</f:for>
So if I would insert multiple images to this I have no real relation between the images where i know which one is the normal-source and which one is the alternate source.
So there was the possibility to create a section and add two fields for images which we can restrict to one image per field. But there again is the for-loop which doesn't allow me to access the source of the second image for the first image.
It should be a visible relation between these images for the user which is working with the dce.
Im trying to achieve something like this:
<f:for each="{field.images}" as="images">
<!-- want to achieve something like this -->
<f:image image="{images.foo.src}" data-altsrc="{images.bar.src}">
<!-- thats the normal way iterating through images -->
<f:for each="{images.foo}" as="image">
<f:image image="{image}" />
</f:for>
</f:for>
Another idea would be to iterate first through the alternate images and store them into an array and on the main-images to access them but I have no idea if this is even possible also this will restrict the usability of the dce for the user.
Is there any way to achieve this with dce-fluid ?
Thanks in advance
Well, i guess you could extend the sys_file_reference table to add a relation from there. So you would have nested relations (never done that, so you would have to try).
You would also have to add the field to the tca type in the place you need it, that could be a little tricky. Have a look at Tca types overrides.
You could extend the sys_file_reference table with a field "alternative_reference" and add the neccessary TCA setup. Then you would have to retrieve the FileReferences via the FileRepository and use sys_file_reference as foreign table (and of course the sys_file_reference uid as identifier).
FileRepository::findByRelation(
'sys_file_reference',
'alternative_reference',
$uidOfActualSysFileReferenceRecord
);
The other possibility would be a completely new record with 2 different sys_file_reference relations. That record (eg: tx_ext_domain_model_imageset) would have an image_default and image_alternate field, both would be configured as file_relations. That would work for sure.
$defaultImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_default',
$uidOfRecord
);
$alternativeImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_alternative',
$uidOfRecord
);
I assume you do have knowledge about creating records, models, tca and so on.
I personally would prefer the second way, it is more clean and does not change the core-table structures.
Also there is a second image generation viewhelper, that might suite your needs better
<img src="{f:uri.image()}" data-altsrc="{f:uri.image()}" />
But the best way to go might be to write your own ViewHelper for that purpose. You could pass your Object (ImageSet) as parameter and handle all logic there. So your template would be simpler and easier to read/work on.
You have to use data attribute of fluid viewhelper and then get the uri of the image with inline call. Here is how to achieve :
<f:image src="{fileReference.uid}" data="{altsrc: '{f:uri.image(src: \'{fileReference.uid}\', treatIdAsReference: 1}" treatIdAsReference="1"/>
This should do the work.

Best way to declare content element uids to use them in fluid templates

I want to display some contentlement on every page with fluid templates. My solution was to create a typoscript element like:
lib.my.myelement= CONTENT
lib.my.myelement {
table = tt_content
select {
pidInList = 15
where = uid=99
}
}
and then use it in the fluid template with:
<f:cObject typoscriptObjectPath="lib.my.myelement" />
Another way is to create them directly in fluid with v:content.render or v:content.get. In this example I get all content elements on one page and save them in an array:
<v:variable.set name="contentElements" value="{v:content.get(column:'0', limit:'3', pageUid:'9', render:'FALSE')}" />
I can not use the first solution, cause on this page there will be much different languages ( I could use it, but every time a new language is added I would have work to declare all new uids of the new elements in typoscript).
The second solution would work better, cause when you translate a page the element uids change, but the pageUid does not change. But here I have the problem that I don't just need all elements, I also have to identify each element.
Here is how I use the second solution:
<v:variable.set name="contentElements" value="{v:content.get(column:'0', limit:'3', pageUid:'9', render:'FALSE')}" />
<f:for each="{contentElements}" as="contentElement" iteration="footerIteration">
<div class="column{v:math.sum(a: footerIteration.index, b: 1)}">
<v:content.render contentUids="{0:contentElement.uid}" />
</div>
</f:for>
As you can see, I use every element the same way.
lets create a simple case:
I have a page with the pageUid = 10 (this page will have translations). On every of this translations will be 3 elements. Lets say 1 element got the "id" (with id I mean something how I can identify this element) title1 and the other two elements have the id list1 and list2.
And my question now is How could I access for example list1?
I hope its understandable, if something is not clear please leave a comment.
Edit: I could use the same order on every translation for the elements and then check the iteration in the for-loop (see the second solution) to identify them. But I wonder if there a better, cleaner way.

Access fluidpage configuration in template

I'm trying to access fluid page configuration inside a template.
In detail: I added a selectfield to my page layout
<flux:flexform.field.select name="pageIcon" items="{
0: {0: '{f:translate(key: \'pageIconNone\')}', 1: ''},
1: {0: '{f:translate(key: \'pageIconFacebook\')}', 1: 'fa-facebook-square'},
2: {0: '{f:translate(key: \'pageIconFlickr\')}', 1: 'fa-flickr'},
3: {0: '{f:translate(key: \'pageIconGooglePlus\')}', 1: 'fa-google-plus-square'}
}"/>
So far so good. Now I render a menu an want to access this field pageIcon
<v:page.menu.directory pages="{settings.pid.socialMenu}" useShortcutData="TRUE" classFirst="first" classLast="last">
<f:for each="{menu}" as="mainPage" iteration="iteration">
<i class="fa {mainPage.pageIcon} fa-2x"></i><b>{mainPage.title}</b>
</f:for>
</v:page.menu.directory>
But this does not work. After some debugging I noticed, that this configuration seems to be stored in tx_fed_page_flexform which holds an XML array.
How can I access the XML values inside my fluid template?
Markus
The easiest way:
https://fluidtypo3.org/viewhelpers/flux/master/Form/DataViewHelper.html
<flux:flexform.data table="pages" field="tx_fed_page_flexform" uid="{pageUid}" as="pageData">
{pageData.pageIcon}
</flux:flexform.data>
The reason for not extracting this data always, is simply for performance. There is another way which you may not be aware of:
<flux:flexform.field.select name="pages.pageIcon" items="{...}" />
If you name your field thusly (the pages. prefix is the key since we are using the pages DB table) your value will be saved into a field in the record itself (a field you must then add in the SQL schema / TCA, and enable value sliding in the rootline if you desire it). If a field with this prefix is saved, Flux will insert its value directly into the pages record which means you can immediately access it using for example {pageVariable.icon} without the need for the flux:flexform.data ViewHelper.
UPDATE
For more recent version of Flux, try:
<flux:form.data table="pages" field="tx_fed_page_flexform" uid="{pageUid}" as="pageData">
{pageData.pageIcon}
</flux:form.data>