How to make circle with break in fluid? - typo3

I want to stop my circle after output first element.
<f:for each="{errors}" as="error">
<f:switch expression="{error.code}">
<f:comment>The given subject was not a valid email address</f:comment>
<f:case value="1221559976">
<f:translate extensionName="helper" key="validator.emailaddress.notvalid" />
</f:case>
...
</f:switch>
BREAK????
</f:for>
Is it possible with fluid? Regards, Anton

You don't even need to iterate the collection, what for? Instead you can just fetch first element like: {errors.0}
Additionally if you want to fetch i.e. first 3 elements, you can prepare $limitedErrors (or smth) in your PHP controller and then assign it into the view.
It will be still more comfortable than manipulating within the template engine.

You can make you for each loop with additional argument iteration=""
add below code
<f:for each="{errors}" as="error" iteration="errorIterator">
and add condition
<f:if condition="{errorIterator.index} = 0">
or
<f:if condition="{errorIterator.isFirst}">

May you can use vhs viewhelper
<v:switch value="{variable}">
<v:case case="someValue" break="TRUE">
<!-- do whatever, if {variable} == 'someValue' -->
</v:case>
<v:case case="default">
<!-- the case "default" is a reserved keyword which acts as the default case. -->
</v:case>
</v:switch>
break > boolean

Related

Typo3 DCE Container loop

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.

TYPO3 Flux - getting content of grid returns nothing

I have a flux-grid that looks like this:
<flux:grid>
<flux:grid.row>
<flux:grid.column name="content" label="Content"/>
</flux:grid.row>
</flux:grid>
It's a wrapper for other content-elements (namely elements of a slider).
Now I need to wrap each of the elements in a <li>-Tag.
So I thought I get the content as an array and render it in an each-loop.
<flux:content.render area="content" as="slides" render="1" />
I thought I'd have the elements in a variable called slides now. But that doesn't seem to be the case. When I use <f:debug>{slides}</f:debug> I get just an empty variable...
Thus, this fails:
<f:for each="{slides}" as="slide">
<f:debug>{slide}</f:debug>
</f:for>
Just outputting the content like this works, though:
<flux:content.render area="content"/>
What am I doing wrong?
[Edit]
I'm one step further...
<v:variable.set name="contentElements" value="{flux:content.get(area:'content', render:'FALSE')}" />
Does indeed return an array with the elements.
But when I try to render the elements, they're empty:
<f:for each="{contentElements}" as="contentElement">
UID: {contentElement.uid}<br />
<v:content.render contentUids="{0:contentElement.uid}" />
</f:for>
the UID is correctly outputted - the v:content.render fails
Seems like I was just using an old Vhs-Version.
Saw in the Extensions that it had an update (to 4.3.3) and now it's working...

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

Dynamicly change TYPO3 fluid Layout by typeNum

I am using the extension fluidpages and want to switch the layout by the typeNum.
is it possible to change the f:layout by by an condition?
This wont work:
<f:layout name="{f:if(condition: '{typeNum} == 666', then: 'PageAjax', else: 'Page')}"/>
Suggested approach:
<f:layout name="Page/{typeNum}"/>
Required files:
Resources/Private/Layouts/Page/0.html
Resources/Private/Layouts/Page/666.html
Please note: this only works if the {typeNum} variable is guaranteed to exist - if it does not, you will face a "template file not found" error with an empty filename. To avoid this, you can use the VHS extension's v:var.convert ViewHelper to ensure a proper value:
<f:layout name="Page/{typeNum -> v:var.convert(type: 'integer')}"/>
I got the same problem recently, and found the solution after a few researchings.
The problem is, you can not use nested fluid like <f:if>, <f:cObject> or others in <f:layout>. Otherwise, you will get a fatal error in the cache file, saying call to a member function getViewHelper() on a non-object. And when you look at the cache file, you will find it's because $self is not defined.
Therefore, my solution is, searching public function getLayoutName( in \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler, and adding \$self = \$this; before \$currentVariableContainer = \$renderingContext->getTemplateVariableContainer();, just like generateCodeForSection()
I have now added the Condition in the Layout template. I get the typeNum from typoscript.
<f:if condition="{f:cObject(typoscriptObjectPath:'plugin.nc_template.settings.pageLayout')} == 'Default'">
<p>Default Template</p>
</f:if>
<f:if condition="{f:cObject(typoscriptObjectPath:'plugin.nc_template.settings.pageLayout')} == 'Ajax'">
<p>Ajax Template</p>
</f:if>
I found an example on the fedext Page, but could not get this to run:
https://fedext.net/blog/archive.html?tx_news_pi1[news]=55&tx_news_pi1[%40widget_0][currentPage]=8&cHash=f9c3165598a28d2aa98fd30ef115bb75
CanĀ“t you use an if-statement instead?
IMHO this is easier to read - and if you need to add more arguments which depends on typeNum, it would stay readable.
<f:if condition="{typeNum} == 666">
<f:then>
<f:layout name="PageAjax">
</f:then>
<f:else>
<f:layout name="Page">
</f:else>
</f:if>

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?