Run TYPO3 Fluid on VueJS component - vue.js

I have a VueJS component and I'm trying to add translated text via Fluid tag.
<div xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">
<h2><f:translate key="search.resultPage"/>"{{mutatedQuery}}".</h2>
</div>
The tags are displayed on frontend, but the <f:translate> tag is empty.

Assumed direction Fluid → Vue
Indeed that's tricky since Fluid does not support escape characters for inference literals like {} which are used in any other client-side frameworks like Vue or Angular as well.
case
Fluid template
rendered output
1
{{item.value}}
ø
2
{{ item.value }}
{{ item.value }}
3
{{<f:comment/>item.value<f:comment/>}}
{{item.value}}
1: empty string (we knew that already)
2: works, adding space between braces and variable name
3: works, since <f:comment/> breaks Fluid inline pattern (but it's "ugly")
Assumed Direction Vue → Fluid
It is not possible to call Fluid (server-side rendering) from Vue (client-side template & document fragment).
Alternative, combining both via slots
It is possible to use Fluid in the base template served by a web server and use slots to inject the content to Vue components, see https://v2.vuejs.org/v2/guide/components-slots.html.
Main Fluid template:
<div
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">
<my-app>
<template v-slot:resultPageLabel>
<f:translate key="search.resultPage"/>
</template>
</my-app>
</div>
Vue my-app component template:
<h2>
<slot name="resultPageLabel"></slot>
"{{mutatedQuery}}".
</h2>

I didn't succeed to integrate Fluid on Vue, I think that both have different rendering engines and can not be synchronize as I wanted.
I solved this issue by adding <f:translate key="search.resultPage"/> as a data-attribute on another tag(that is not rendered in vue) and get that translates on vue component.

Related

Vue without root element

How implement a component that doesn't output a root element, like the vuetify tooltip or And design, in vue 2.x? And perhaps it's not a functional component.
<my-tooltip text="Tooltip">
<my-button>Button</my-button>
<my-tooltip>
to
<my-button>Button</my-button>
<div class="tooltip">Tooltip></div>
I don't have the skills to fully parse the vuetify source.
I would appreciate it if you could show me a simple demo.
In Vue 2, you have to have only one root element whereas it's not required in Vue 3. You can wrap your html in a div or a v-container or whatever:
<v-container>
<my-button>Button</my-button>
<div class="tooltip">Tooltip></div>
</v-container>

Image not showing in vue and vue bootstrap

I want to get image from assets folder in vue and
Im using vue bootstrap
Here is my code :
<b-card title="Title" img-src='#assets/profile.jpg' img-alt="Image" img-top>
<b-card-text>
This is a wider card with supporting text below as a natural lead-in to additional content.
This content is a little bit longer.
</b-card-text>
<template v-slot:footer>
<small class="text-muted">Last updated 3 mins ago</small>
</template>
</b-card>
Here is my hirarcy
But it not working. Can someone help me?
To use relative paths for the various img (img-src in this case) props in bootstrap-vue components, you need configure vue-loader as explained in the documentation here.
This should fix the issue you're facing.
If you cannot set the transformAssetUrls for vue-loader, you can require as an alternative.
<b-card :img-src="require('../static/picture.jpg')"></b-card>

Does Vuejs allow to use nested template tag?

Is it allowed to use <template> tag inside template something like this?
I have to check some value.
<template>
<div>
<template v-for="category_field in category_fields">
<template v-if="category_field.show_type == 'new-row'">
//and also here can be more nested template tags
</template>
<template v-else>
//and also here can be more nested template tags
</template>
</template>
</div>
</template>
I am using this system in my project and wondering whether this is correct.
Yes, you can nest <template>s, and it's quite useful sometimes.
Vue's <template> is very similar to <React.Fragment>. It's a virtual container used for grouping or applying layout logic (using structural directives - e.g: v-for, v-if), without creating an actual DOM element.
Because it doesn't output a DOM element, it's used as a wrapper for SFC's HTML markup.
Technically, the limit on having only one child in Vue 2 was not coming from the <template> tag itself, but from the components, as Vue required them to have only one root element, which became the component's $el. More detail here.
Besides the typical usage of wrapping an SFC's markup, <template> tags are also used for:
combining structural directives (v-for, v-if) and letting Vue know in which order to apply the directives, as changing the order would likely change the result
applying layout or rendering logic (e.g: v-if) to multiple elements at once, without having to create an actual DOM wrapper around them, particularly useful when you don't want to break the parent/child relation of DOM elements (e.g: flex or grid parent/children, <ul>/<ol> + <li>, <tr> + <td>, <tbody> + <tr>, etc.).
reducing template boilerplate (e.g: moving the same v-if from multiple siblings on a <template> wrapper, so the condition is only written once).
Try using this. <template> require only one child.
<template v-for="category_field in category_fields">
<div>
<template v-if="category_field.show_type == 'new-row'">
//and also here can be more nested template tags
</template>
<template v-else>
//and also here can be more nested template tags
</template>
</div>
</template>

Vue 2.0 server-side-render with template inside #app container

Server side rendering page for reference: ssr.html
Now the problem, what if we want to define template inside the <div id="app"></div> in html file itself, not in Vue instance template property? Like this:
<div id="app">You have been here for {{ counter }} seconds.</div>
In this case if we want to pre-render it, we will get next pre-rendered html:
<div id="app" server-rendered="true">You have been here for 0 seconds&period;</div>
And here is the conflict problem. If we will output pre-rendered html, we lose our template and Vue doesn't know where to output counter inside our <div id="app">.
Is it possible somehow to provide template inside <div id="app"></div> container and in the same time pre-render it? Or provide template near the pre-rendered in html(so Vue will know that here is pre-rendered and here is template and i will use it if any changes happens in the model)?
Is it possible somehow to provide template inside container and in the same time pre-render it? Or
Short but complete answer: No. For Vue SSR, you cannot use in-DOM templates. You have to use string-based templates (including Single File Components).

Oddity with templates and root node with vue.js

I think this is possibly a bug I've stumbled across, not sure. I'm getting this Vue.js warning for a component:
vue.js:2611 [Vue warn]: Cannot use <template> as component root element because it may contain multiple nodes:
The problem seems to be this:
<template id="tpl-field">
<template v-if="fieldType==='checkbox-inline'">
<label class="checkbox-inline">[SNIP]</label>
</template>
<template v-else>
[SNIP]
</template>
</template>
So I have two template nodes, which seems to be the multiple nodes it's choking on (certainly each of the template nodes contains just a single node). Yet this is an if-else in Vue - if one of the nodes is present, the other logically cannot be.
Demo of the problem here: https://jsfiddle.net/jonmor51/Ldz3k0jp/1/. If I wrap everything in a div, it works. But without, it fails. (Unfortunately, in the context where I want to use this, namely for inline checkboxes within a Bootstrap grid, wrapping in a div breaks things).
Not sure if this will solve your problem with bootstrap... but you could wrap you inner templates with a <transition> tag and set a key to each one.
Please check this working fiddle
https://jsfiddle.net/AldoRomo88/7c7znu3p/
helpful thing - just use div display: contents as a root of the component and browser will ignore that element and consider child elements (which can be many) as children of upper dom element
<div style="display: contents">
<template v-if="...">
<template v-for="..."> ...
</template>
<template v-if="...">
</template>
</div
works even inside tables!
The inner templates direct children, are they single elements? If so, you can just remove the inner templates and move v-if to the label.
Or, just use span rather than div as your quick fix, which won't break inline elements' style.