vuejs template conditional root element - vue-router

I'm making a generic vue button component.
In some cases it would be a router-link while in other cases it would be a normal anchor tag.
So basically looking for something like this.
<template>
<router-link v-if="useRouter" :to="link"></router-link>
<a v-else :href="link"></a>
</template
But a vuejs component template must have exactly one root element.
Besides making two seperate vue components or wrapping my button in an element. I can't think of any other solution.
Is there a better way to solve this?

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>

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>

Difference between routing inside v-btn and using router-link

I am learning Vue.js, and, following a tutorial, a is used to route the page to another. He used a button wrapped by this tag, and I found that using the routing directive inside the tag.
I was wondering, what's the difference between this two ways of going from one page to another? Both of them seems to be producing the same behavior (and I am not sending or receiving any data when changing pages).
Codes for comparison:
Using v-btn
<v-btn :to="{name: 'songs-create'}"
dark medium right bottom fab absolute
class="pink" slot="action">
<v-icon>add</v-icon>
</v-btn>
Using router-link
<router-link :to="{name: 'Hello'}" tag="span" class="logo">Tab Tracker</router-link>
Thanks in advance!
v-btn is a component of vuetifyjs whereas router-link is component of vue-router.
When you use v-btn with to attribute by passing the path object, it internally uses the vue-router's router-link component's api.
So v-btn wraps the functionality of router-link when it is used with to attribute.
The reason why he could have been used the v-btn is to accomplish some other stuff like button styles and handling other events etc.

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.

Applying v-transition to vue.js(v 1.0.1) router-view

I'm building a single page application, using vue.js and vue-router.. right now the links work, but I want to add transition using v-transition.
but according to the documentation
What’s more important though, is that non-flow-control directives, non-prop attributes and transitions on the component element will be ignored, because there is no root element to bind them to - vue.js components
<router-view class="bounce" v-transition="bounce" transition-mode="out-in"></router-view>
so technically the v-transition in the router-view tag will be ignored because it is a Fragment instance..
so any idea where I can put the v-transition to apply transitions on route change?
Define at least one route node in your component:
<router-view class="bounce">
<div v-transition="bounce" transition-mode="out-in">
</div>
</router-view>
Vue need one element to insert in the DOM if you want to apply transition, or v-show.