How to assign variable in fluid? - typo3

I want viewhelper that can be helpful to assign variable in fluid, I dont want variable to be passed from controller.

Install extension called vhs from TYPO3 repository
Define namespace like following at the top of your fluid template
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
Then use set viewhelper
<v:variable.set name="test" value="12345" />
Value of test : {test}
{test} will return value 12345
For registering global variable
<v:variable.register.set name="test" value="12345"/>]
Get value of global variable
Value of global variable : <v:variable.register.get name="test">
Since TYPO3 8.7, fluid introduces viewhelper for the variable (No need
of VHS)
<f:variable name="myvariable">My variable's content</f:variable>
<f:variable name="myvariable" value="My variable's content"/>
With inline style usage
{f:variable(name: 'myvariable', value: 'My variable\'s content')}
{myoriginalvariable -> f:variable.set(name: 'mynewvariable')}

Since TYPO3 8.6, this is possible without extension "vhs":
<f:variable name="myvariable" value="My variable's content"/>
See https://docs.typo3.org/typo3cms/extensions/core/Changelog/8.6/Feature-79402-VariableViewHelperForFluid.html

Since first fluid version it is possible to define variables for a special area: there is the VH f:alias which enables you to define new variables in the range of this VH. And that is the difference to the variable.set VH from ext:vhs.
<f:alias map="{firstName: 'John', lastName: 'Doe'}">
<p>Hello, my name is {firstName} {lastName}</p>
</f:alias>
<f:for each="{users}" as="user" iteration="iterator">
<f:if condition="{iterator.isFirst}">
<v:variable.set name="firstName">{user.firstName}</v:variable.set>
<v:variable.set name="lastName">{user.lastName}</v:variable.set>
</f:if>
:
do other output
:
</f:for>
<p>the first user was {firstName} {lastName}.</p>
The problem with setting variables inside the fluid is the possibility to do programming logic inside fluid:
<v:variable.set name="counter" value="0">
<f:for each="records" as="record">
<f:if condition="{record.flag}">
<v:variable.set name="counter">
<f:cObject typoscriptObjectPath="lib.calc">
{counter}+1
</f:cObject>
</v:variable.set>
</f:if>
</f:for>
<p>there are {counter} records with a flag set.</p>
with this typoscript
lib.calc = TEXT
lib.calc.current = 1
lib.calc.prioriCalc = 1

Related

TYPO3 Form Framework e-mail-finisher with staticText

I made a form with the TYPO3-FormFramework (Version 10.4.12). The form contains a lot of staticText-Elements, which don't show up at the summary-page and in the emails. The Template-part looks like this
<formvh:renderAllFormValues renderable="{form.formDefinition}" as="formValue">
...
{formvh:translateElementProperty(element:formValue.element, property: 'label')}
...
<f:if condition="{formValue.value}">
<f:then>
<f:if condition="{formValue.isMultiValue}">
<f:then>
...
<f:for each="{formValue.processedValue}" as="value">
<tr>
<td>{value}</td>
</tr>
</f:for>
</table>
</f:then>
<f:else>
<table>
<tr>
<td>
<f:format.nl2br>formValue.processedValue}</f:format.nl2br>
...
</formvh:renderAllFormValues>
(identical with the original-Template.)
The Formdefinition in the yaml-File containts standard definitions like
renderables:
-
properties:
text: 'Antrag auf Mitgliedschaft'
elementClassAttribute: h3
type: StaticText
identifier: statictext-10
label: ''
-
Does anyone know how to output the staticTexts (and/or contentElements used in forms)?
Thanks a lot
In Configuration/Yaml/FormElements/StaticText.yaml, the YAML configuration of the StaticText field includes a Form variant:
variants:
-
identifier: hide-1
renderingOptions:
enabled: false
condition: 'stepType == "SummaryPage" || finisherIdentifier in ["EmailToSender", "EmailToReceiver"]'
This variant will disable the rendering of the field if the condition is met, in this case:
on a summary page
in the two email finishers
You can learn more about Form variants in the official documentation.
Possible solution
First of all, we need to alter the variant of the field type StaticText in your custom Form configuration:
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
StaticText:
variants:
-
identifier: hide-1
renderingOptions:
enabled: true
This change already allows to render the StaticText's Header (label) in summary pages and emails. But the text value is still missing, as only processed values (means: user input) are rendered there.
To also render the value stored in the Text field, we need to extend the Fluid templates. The following partial will work in SummaryPage.html, as well as in the email finisher templates:
<f:if condition="{formValue.value}">
<f:then>
[default processing here]
</f:then>
<f:else>
<f:if condition="{0: formValue.element.type} == {0: 'StaticText'}">
<f:then>
{formValue.element.properties.text}
</f:then>
<f:else>
-
</f:else>
</f:if>
</f:else>
</f:if>
As you can see, we add another condition which checks if the current form element in the f:for loop is of type StaticText. If this is the case, we render the text property. For all other field types with an empty value, we still render the hyphen.

Check if pid of current page is X

How can I check if a page has a specific ID, and if true output a text?
I thought about something like this (pseudocode):
<f:if condition="{current.page.uid}=='78'">
<p>I am Page 78</p>
</f:if>
If you want to use this in an FLUIDTEMPLATE (page.10 = FLUIDTEMPLATE as example) you can access the page data with {data.uid}.
<f:if condition="{data.uid} == 78">
<p>I am Page 78</p>
</f:if>
In an extbase Extension you can make it like #dimitri-l says.
You can fetch current page ID via typoscript object
typoscript:
lib.currentPageId = TEXT
lib.currentPageId.data = TSFE:id
FLUID:
<f:if condition="{f:cObject(typoscriptObjectPath:'lib.currentPageId')}==78">
<p>I am Page 78</p>
</f:if>
You can make a variable into your "page TS setup" like here :
variables {
pageUid = TEXT
pageUid.field = uid
...
}
So you can make your fluid condition as here :
<f:if condition="{pageUid}=={settings.homepid}">
<p>I am Page 78</p>
</f:if>
for exemple...
You would need to pass the page id to the fluid template. If you are using an Extbase controller you can pass $GLOBALS['TSFE']->id to your view and then use an if condition as you did.
$this->view->assign('pageId', $GLOBALS['TSFE']->id);
I am not sure if it is already possible to do string comparison in Typo3 6.2, if not, you have to compare it that way:
<f:if condition="{0:pageId} == {0:'78'}>
...
</f:if>
Otherwise this is a clean solution for current versions
<f:if condition="{pageId} == '78'>
...
</f:if>
With the VHS viewhelper you can do it with fluid only, no need for a Typoscript helper:
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<f:if condition="{v:page.info(field: 'uid')} == '21'">
<f:then>
Shows only if page ID equals 21.
</f:then>
</f:if>
Sometimes you need to give a link a class when the link target is the current page (here: uid=1). The inline version helps:
<f:link.page pageUid="1"
class="{f:if(condition: '{data.uid} == 1', then: ' current')}">
Link
</f:link.page>

Add one more argument for fluid viewHelper by condition

In my fluid template I have:
<f:form.textfield
id="{propertyName}"
property="{propertyName}"
value="{value}"
placeholder=""
class="form-control"
/>
I want to add condition for "value". Something like:
<f:form.textfield
id="{propertyName}"
property="{propertyName}"
<f:if condition="{value}"> value="{value}" <f:if>
placeholder=""
class="form-control"
/>
For now I'm using workaround
<f:if condition="{value}">
<f:then>
<f:form.textfield id="{propertyName}" property="{propertyName}" value="{value}" placeholder="" class="form-control" />
</f:then>
<f:else>
<f:form.textfield id="{propertyName}" property="{propertyName}" placeholder="" class="form-control" />
</f:else>
</f:if>
But I'd like to avoid double code.
I think this is not possible in this way.
Possible solution is user defined ViewHelper (exclude original f:form.textfield).
Developing a custom ViewHelper
Nesting ViewHelpers in their XML notation is not possible. However, you can use the inline notation, at least to a certain extent:
<f:form.textfield
value="{f:if(condition: '<your-condition>', then: value)}" />
Yes, the value attribute will still be passed this way, however, with a null value. Note that the <f:form.textfield> view helper automatically omits the value attribute if the submitted value is empty (see the source code of TYPO3\CMS\Fluid\ViewHelpers\Form\TextfieldViewHelper, line 74ff.):
public function render($required = false, $type = 'text')
{
// [...]
$value = $this->getValueAttribute();
if ($value !== null) {
$this->tag->addAttribute('value', $value);
}
In the simple case that you just want to omit the value attribute when it's empty, just always passing value="{value}" should suffice. When the value is null, the attribute will not be included in the rendered <input> tag.
You can do it like this:
<f:form.textfield
name="{data.name -> f:format.urlencode()}"
type="{f:if(then: '{data.inputtyp}', else: 'text', condition: '{data.inputtyp}')}"
class="{f:if(then: '{data.class}', else: '', condition: '{data.class}')}"
value="{f:if(then: '{data.populate}', else: '', condition: '{data.populate}')}"
placeholder="{f:if(then: '{data.placeholder}', else: '', condition: '{data.placeholder}')}" />

How to use typoscript object in fluid template as if condition

I have a typoscript TEXT object:
lib.myid = TEXT
lib.myid.value = 1413
And want to use it in a fluid template (for tx_news):
<f:for each="{newsItem.categories}" as="category">
<f:if condition="{category.uid} == {lib.myid}">
Category ID is the same as myid
</f:if>
</f:for>
How can I do this?
You can use the ViewHelper f:cObject. It would look like this:
<f:for each="{newsItem.categories}" as="category">
<f:if condition="{category.uid} == {f:cObject(typoscriptObjectPath: 'lib.myid')}">
Category ID is the same as myid
</f:if>
</f:for>
Alternatively, you can make the value a setting of the news plugin, by setting
plugin.tx_news {
settings {
valuefromlibrary < lib.myid
}
}
Afterwards, you can access the value using {settings.valuefromlibrary} in your template. But beware that the settings are not automatically passed on to partials, so in a partial the value might not be defined. This restriction is circumvented in the default template of EXT:news by passing the settings-variable to partials.

How do I check for column content in a typo3 fluid template?

I have a typo3 fluid template in which I want to check if content exists before rendering some elements.
Is there an efficient way to do this?
eg.
<f:if condition="{contentInColPos0}">
<div class="section-content">
<f:render section="Main" />
</div>
</f:if>
Is there a built-in variable or a simple way to check content exists in a column position?
This is a common task in CMS templating (don't render this part unless there's something to show), but I can't seem to find how to do it simply.
There is no easy way to do that. But you can use some TypoScript and then pass the count to Fluid and use it in a condition:
lib.countContent = CONTENT
lib.countContent {
table = tt_content
select {
selectFields = count(uid) AS count
pidInList = this
andWhere = (deleted = 0 AND hidden = 0)
}
renderObj = COA
renderObj {
10 = TEXT
10 {
data = field:count
}
}
This object will output the number of content rows on the given page and can be accessed in Fluid:
<f:if condition="{f:cObject(typoscriptObjectPath:'lib.countContent')} > 0">
Then show some stuff
</f:if>
If you're going to use the content anyway and don't have global wrap in your content object, you can also use it directly because the Fluid IfViewHelper checks for empty strings. So e.g. this might be working even better:
lib.content < styles.content.get
(This object is empty if there is no content)
<f:if condition="{f:cObject(typoscriptObjectPath:'lib.content')}">
<f:then>
<f:format.html>{lib.content}</f:format.html>
</f:then>
<f:else>
No content found
</f:else>
</f:if>
Easyest way to check this with VHS and without TypoScript:
<f:if condition="{v:content.get(column:6) -> v:iterator.first()}">
<div class="myAmazingClass">
</div>
</f:if>
You can slide the content throug subpages if you want:
<f:if condition="{v:content.get(column:6, slide:'-1') -> v:iterator.first()}">
<div class="myAmazingClass">
</div>
</f:if>
Consider VHS with ViewHelpers https://fluidtypo3.org/viewhelpers/vhs/master/Content/GetViewHelper.html or https://fluidtypo3.org/viewhelpers/vhs/master/Content/RenderViewHelper.html combined with using the as argument and an f:if condition to check the assigned variable for being empty.
You can solve this easily:
In your TypoScript file:
lib.contentInColPos0 < styles.content.get
lib.contentInColPos0 t.select.where = colPos = 0
In your Template file:
<f:if condition="{f:cObject(typoscriptObjectPath:'lib.contentInColPos0')}">
<div class="section-content">
<f:render section="Main" />
</div>
</f:if>