Typo3 DCE Container loop - typo3

I want to make this code more flexible.
As you maybe can see, it's a code for DCE.
So I want to make it possible to add Quotes with a loop or some kind similar.
https://gist.github.com/DarthKeks/f5b3c9c26f05f3a8dfbf127dee9f9b64

In DCE you can use a section that repeats itself. Say you create a section with the variable quote
Navigation
Iterator can be anything, this allows you to loop an do stuff like
counting or numbering. We use the iterator to see if an item is the
first item, and add an active class.
For example:
<ol class="carousel-indicators">
<f:for each="{field.quote}" as="quote" iteration="iterator">
<li data-target="#quote-carousel" data-slide-to="{iterator.cycle}" {f:if(condition: '{iterator.isFirst} == 1', then: ' class="active"')}></li>
</f:for>
</ol>
Caroussel
Same principle applies here:
<div class="carousel-inner" role="listbox">
<f:for each="{field.quote}" as="quote" iteration="iterator">
<div class="item{f:if(condition: '{iterator.isFirst} == 1', then: ' active')}">
<blockquote>
<f:format.html>{quote.expert}</f:format.html>
<small>{quote.expertName}</small>
</blockquote>
</div>
</f:for>
</div>

you can simply use dce-containers Where your qoutes are now just add a
Marker/Field and load in your DCE fields into that Marker/Field. As long as the DCE item is the same type it will loop trough.

Related

Unwanted hidden field and missing for attribut in checkbox (TYPO3, Powermail)

I have a problem with TYPO3/Powermail. I tried to add custom checkbox images and ran into problems with IE. I found another website based on TYPO3 with customized checkboxes working fine on IE too.
What is weird is, that my html form structure (generated by TYPO3/Powermail) looks different.
Here is my checkbox html:
As you can see, I have a field with type hidden inserted, don't know why. And my label has no "for" attribut.
This form field here (TYPO3/Powermail as well) looks nice:
Here we have no strange hidden input field, and there is a "for" attribut in the label.
Can someone help?
The templates of the both installations differ. Check the original templates and partials delivered with EXT:powermail in folder EXT:powermail/Resources/Private. If you use own templates add all needed fields and options.
For example add the for-attribute to the <label> in partial for radio buttons: <label for="powermail_field_{field.marker}_{index.cycle}">.
In newer versions of EXT:powermail (7.3.1) file Resources/Private/Partials/Form/Field/Radio.html looks like:
{namespace vh=In2code\Powermail\ViewHelpers}
<div class="powermail_fieldwrap powermail_fieldwrap_type_radio powermail_fieldwrap_{field.marker} {field.css} {settings.styles.framework.fieldAndLabelWrappingClasses}">
<f:render partial="Form/FieldLabel" arguments="{_all}" />
<div class="{settings.styles.framework.fieldWrappingClasses}">
<f:for each="{field.modifiedSettings}" as="setting" iteration="index">
<div class="{settings.styles.framework.radioClasses} {vh:Validation.ErrorClass(field:field, class:'powermail_field_error')}">
<label>
<f:form.radio
property="{field.marker}"
value="{setting.value}"
checked="{vh:Misc.PrefillMultiField(field:field, mail:mail, cycle:index.cycle)}"
id="powermail_field_{field.marker}_{index.cycle}"
additionalAttributes="{vh:Validation.ValidationDataAttribute(field:field, iteration:index)}"
class="powermail_radio" />
<vh:string.escapeLabels>{setting.label}</vh:string.escapeLabels>
</label>
</div>
</f:for>
<f:if condition="{settings.validation.client}">
<div class="powermail_field_error_container powermail_field_error_container_{field.marker}"></div>
</f:if>
</div>
Resources/Private/Partials/Form/FieldLabel.html:
{namespace vh=In2code\Powermail\ViewHelpers}
<f:comment>
Partial file for the HTML-structure of nearly all field labels
</f:comment>
<f:if condition="{field.css} != 'nolabel'">
<label for="powermail_field_{field.marker}" class="{settings.styles.framework.labelClasses}" title="{field.description}">
<vh:string.escapeLabels>{field.title}</vh:string.escapeLabels><f:if condition="{field.mandatory}"><span class="mandatory">*</span></f:if>
</label>
</f:if>

Get next news record in Fluid Template?

I am creating a custom news template for tx_news which uses a Fluid Template.
I need to get the uid of the next news record in the loop.
<f:for each="{news}" as="newsItem" iteration="iterator">
<div id="{newsItem.uid}">
Go to next
</div>
</f:for>
You could use the extension vhs, it provides a ton of useful ViewHelpers - among them the ViewHelper v:iterator.next. I've never used it, but from reading the documentation I'd use it like this (using the ViewHelper v:variable.set from the same extension for a creating a local variable):
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<f:for each="{news}" as="newsItem" iteration="iterator">
<div id="{newsItem.uid}">
<v:variable.set name="nextNews" value="{news -> v:iterator.next(needle: newsItem)}"/>
Go to next
</div>
</f:for>

TYPO3 fluid_styled_content - Menu when using gridelements

how can i build a TYPO3 special-Menu in fluid with tt_content Header Elements, not the "pages" ?
https://docs.typo3.org/typo3cms/extensions/fluid_styled_content/7.6/ContentElements/Menu/Index.html
The Type-3 is a good Example, but i can only selected in the BE the Pages, not the tt_content - Elements.
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:ce="http://typo3.org/ns/TYPO3/CMS/FluidStyledContent/ViewHelpers" data-namespace-typo3-fluid="true">
<ce:menu.list pageUids="{pageUids}" as="pages">
<f:if condition="{pages}">
<ul class="ce-menu ce-menu-3">
<f:for each="{pages}" as="page">
<ce:menu.section pageUid="{page.uid}" as="contentElements" type="header">
<f:if condition="{contentElements}">
<f:for each="{contentElements}" as="contentElement">
<li>
<f:link.page pageUid="{page.uid}" section="c{contentElement.uid}">
{contentElement.header}
</f:link.page>
</li>
</f:for>
</f:if>
</ce:menu.section>
</f:for>
</ul>
</f:if>
</ce:menu.list>
</html>
I suppose you get back content elements which have "Show in Section Menus" enabled, and have the header filled and not hidden. The menu.section viewhelper does not have the possibility to filter on content element type. The type="header" argument of the view helper is not a filter for the content element type, but checks if there is a visible header_layout and the header field is not empty. I agree, the argument name type is misleading.
If you want to filter on content type (CType), add an extra "if" statement, filtering on {contentElement.CType} == header during the iteration of the content elements
<f:for each="{contentElements}" as="contentElement">
<f:if condition="{contentElement.CType} == 'header'">
<li>
<f:link.page pageUid="{page.uid}" section="c{contentElement.uid}">
{contentElement.header}
</f:link.page>
</li>
</f:if>
</f:for>
Better would be to write your own view helper for this, if you have the knowledge to do it.
First of all you should rename your question so it is clear that you want to create a content menu that works with grid_elements
I had the same problem and could not find another way but to create a small extension for that purpose since you have to modify the search query for the content. You can find it here: https://typo3.org/extensions/repository/view/gridelements_content_menu
There is currently no manual, just install the extension and include the static TS in your template. The resulting Menu might not be sorted right if your content elements are nested deeper than one level with grid_elements

Use v:content.render in a Contentelement

I try to render some Elements from another page via fluid in a Partial and try to use v:content.render. As you can see in the code I want to render 3 elements from the page with the Uid 9. But as soon as I have the v:content.render element in it I just get a blank page.
So my question is how to use v:content.render or what alternative I have? Or do I still need to use Typoscript for that?
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<div class="footer2">
<v:content.render column="0" limit="3" pageUid="9" as="contentElements">
<f:for each="{contentElements}" as="contentElement" iteration="footerIteration">
<f:format.html>{contentElement.bodytext}</f:format.html>
</f:for>
</v:content.render>
</div>
I am not sure if it is important, but the elements on the Page 9 are also fluid content elements.
I found a solution that works:
<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">
<v:content.render contentUids="{0:contentElement.uid}" />
<f:format.html>{contentElement.bodytext}</f:format.html>
</f:for>
I think your first attempt was more readable. {contentElement} already had what you needed, there is no property bodytext if you leave render to its default true.
<v:content.render column="0" pageUid="9" limit:"3" as="contentElements">
<f:for each="{contentElements}" as="contentElement">
<f:format.raw>{contentElement}</f:format.raw>
</f:for>
</v:content.render>
If you don't know what you get back in as="" to work with, just try a debug:
<v:content.render column="0" pageUid="9" limit:"3" as="contentElements">
<f:for each="{contentElements}" as="contentElement">
<f:debug inline="true">{contentElement}</f:debug>
</f:for>
</v:content.render>
And I replaced <f:format.html> with <f:format.raw> so prevent some unwanted <p></p>

In TYPO3 Fluid, how do I access a variable from inside a foreach loop?

I am building a navigation with the VHS Menu ViewHelper. Below is the entire code.
My question is probably very basic fluid though.
Inside a scope, how do I access a variable that exists outside that scope - or how do I pass it into that scope?
EDIT: I've updated my code to not use dashes in variable names as well as assigned different names to v:page.menu with as="menuLevel0".
The full code:
{namespace v=Tx_Vhs_ViewHelpers}
<ul id="nav" class="grid-full classic">
<v:page.menu as="menuLevel0" expandAll="1" useShortcutData="1" levels="4" classHasSubpages="parent" classFirst="first" classLast="last">
<f:for each="{menuLevel0}" as="itemLevel0" iteration="iterLevel0">
<li class="{itemLevel0.class} level0 nav-{iterLevel0.cycle} level-top">
<a href='{itemLevel0.link}' class='level-top'><span>
<f:if condition="{itemLevel0.nav_title}"><f:then>{itemLevel0.nav_title}</f:then><f:else>{itemLevel0.title}</f:else></f:if>
nav-{iterLevel0.cycle}</span>
</a>
<f:if condition="{itemLevel0.hasSubPages}">
<f:then>
<v:page.menu as="menuLevel1" expandAll="1" classHasSubpages="parent" classFirst="first" classLast="last">
<ul class="level0">
<f:for each="{menuLevel1}" as="itemLevel1" iteration="iterLevel1">
<li class="{itemLevel1.class} level1 nav-{iterLevel0.cycle}-{iterLevel1.cycle}">
<a href='{itemLevel1.link}' class='level-top'><span>
<f:if condition="{itemLevel1.nav_title}"><f:then>{itemLevel1.nav_title}</f:then><f:else>{itemLevel1.title}</f:else></f:if>
nav-{menuLevel0.iterLevel0.cycle}-{iterLevel1.cycle}
</span></a>
</li>
</f:for>
</ul>
</v:page.menu>
</f:then>
</f:if>
</li>
</f:for>
</v:page.menu>
</ul>
In fluid, variables are and should be scoped to the blocks you are using.
While you are using our v:page.menu ViewHelpers, you need to understand the scoping a bit further:
Use different names for variables in nested scopes: {levelOneIterator} and {levelTwoIterator} are good examples for such behaviour
As a rule of thumb: Use lowerCamelCased variable names. It prevents fluid from parsing your var-names wrong.
The reason why your code is not working:
You assign a {iter} variable. Therefore fluid doesn't parse the dash-ified variable name as it detects the undashified identifier first. Dashes have special meaning in fluid and you can run into kind-of race conditions there.
To take this a bit further:
```
{foo-bar} // echos "baz"
{foo-bar} // echos "bing", as the bar vaiable is read first, and "foo-" isnt a variable in the current scope
```
Update:
Accessing variables from a parent scope doesnt require prefixing your var-call. In a child for-loop, you can access the parent iteration by simply calling the var.
<f:for each="{iterable}" as="iterableItem iteration="iteratorRoot">
{iteratorRoot.index} <!-- Echoes the current, zero-indexed iteration -->
<f:for each="{iterableItem}" as="subItem" iteration="iterationChild">
<!-- STILL echoes the current, zero-indexed iteration -->
{iteratorRoot.index}
<!-- Echoes the current, zero-indexed sub iteration -->
{iterationChild.index}
</f:for>
</f:for>
As long as you give different names to the iterators, you can access them in any scope by their originating name. Same goes for the aliased (as="name") named variables.
Try not using "-" in the variable-name! Use CamelCase instead:
<f:render section="layer2" arguments="{uid: curPage.uid, parentIter: iter.cycle}" />
In Controller
public function listAction() {
$events = $this->eventsRepository->getEventsList();
$this->view->assign('eventsList', $events);
}
In View File you can access like this.
<f:for each="{eventsList}" as="events">
<tr>
<td> {events.event_id} </td>
<td> <f:link.external uri="{events.event_link}" target="_blank">{events.event_link}</f:link.external></td>
<td><f:format.date format="d-m-Y">{events.event_date}</f:format.date></td>
</tr>
</f:for>
Have you tried not to use the same varibale name for the iterators in both of your foreach loops?