Vuejs TransitionGroup error: children must be keyed - vue.js

I have a unique child Div inside a TransitionGroup element in Vue. This Div is keyed. I get this error:
runtime-core.esm-bundler.js?d2dd:38 [Vue warn]: <TransitionGroup> children must be keyed.
I have read other posts on the same error but the problem is usually that the immediate child isn't keyed. In this case the immediate child is keyed, and there is only one immediate child. I thought adding a key to it would be enough? I dont see what's wrong. Thanks for any hint!
<template>
<!--begin: Vue list animation-->
<TransitionGroup name="list" tag="div">
<!--begin: Tag list-->
<div class="d-flex align-items-start mb-4 mt-10" v-for="tag in sortedTagList" :key="tag.id">
<!--begin::Tag name-->
<div class="flex-grow-1 ">
<span href="#" class="badge badge-light">{{ tag.tagname }}
<!--begin::Svg Icon (delete btn) | path: /var/www/preview.keenthemes.com/kt-products/docs/metronic/html/releases/2022-08-29-071832/core/html/src/media/icons/duotune/arrows/arr011.svg-->
<span class="svg-icon svg-icon-muted ms-3 svg-icon-xs custompointer mt-1"
#click="deleteTag(tag.id)">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect opacity="0.5" x="6" y="17.3137" width="16" height="2" rx="1"
transform="rotate(-45 6 17.3137)" fill="currentColor" />
<rect x="7.41422" y="6" width="16" height="2" rx="1" transform="rotate(45 7.41422 6)"
fill="currentColor" />
</svg>
</span>
<!--end::Svg Icon (delete btn)-->
</span>
</div>
<!--end::Tag name-->
<!--begin: User who added-->
<div class="symbol symbol-circle symbol-25px">
<img src="temp" alt="img">
</div>
<!--end: User who added-->
</div>
<!--end: Tag list-->
</TransitionGroup>
<!--end: Vue list animation-->
</template>
<script>
export default {
}
</script>
<style>
</style>

Related

How to overcome: 'v-slot' directive must be owned by a custom element, but 'slot' is not.eslint-plugin-vue?

I have Vue.js app and the key part of the code of component looks as following:
specific-modal.vue:
<template>
<v-modal-dialog
:visible="isModalVisible"
title="CONNECTION"
okText="Save"
cancelText="Cancel"
:isSaveDisabled="isDisabled"
:width="550"
:height="620"
#ok="onOk"
#cancel="onCancel"
#hiding="onHiding"
>
...
base-modal.vue:
<template>
<DxPopup
v-bind="$attrs"
:hide-on-outside-click="true"
:drag-enabled="true"
:wrapper-attr="popupAttributes"
position="center"
v-on="$listeners"
#hiding="onHiding"
>
<slot />
<slot name="footer">
<DxToolbarItem template="save-template" toolbar="bottom" location="after" />
<template #save-template>
<DxButton text="Ok" #click="onOk" />
</template>
<DxToolbarItem template="cancel-template" toolbar="bottom" location="after" />
<template #cancel-template>
<DxButton text="Cancel" #click="onCancel" />
</template>
</slot>
</DxPopup>
</template>
<script>
import { DxPopup, DxToolbarItem } from "devextreme-vue/popup";
import DxButton from 'devextreme-vue/button';
...
The #save-template is underlined with red line and there is a message:
'v-slot' directive must be owned by a custom element, but 'slot' is not.eslint-plugin-vue
How to overcome this isssue?
EDIT:
If I do as following:
<slot />
<slot name="footer">
<DxToolbarItem template="save-template" toolbar="bottom" location="after" />
<custom-element>
<template #save-template>
<DxButton text="TEST" #click="onOk" />
</template>
</custom-element>
<DxToolbarItem template="cancel-template" toolbar="bottom" location="after" />
<custom-element>
<template #cancel-template>
<DxButton text="Cancel" #click="onCancel" />
</template>
</custom-element>
</slot>
When I run the app, I'm getting the following error:
[Vue warn]: Unknown custom element: <custom-element> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I'm not sure how to do it.
<template #save-template is a shorthand for <template v-slot='save-template'.
So the eslint rule is complaining that the <template v-slot='save-template' is owned (has a parent) that is not a custom element (which is ).
<slot> is a like a placeholder that external components can use to add data. But in your code it seems like you are saying a placeholder has provided a placeholder inside it.
To overcome this either change parent slot tag to something else. Or, wrap template tag in a tag like:
<template>
<DxPopup
v-bind="$attrs"
:hide-on-outside-click="true"
:drag-enabled="true"
:wrapper-attr="popupAttributes"
position="center"
v-on="$listeners"
#hiding="onHiding"
>
<slot />
<slot name="footer">
<DxToolbarItem template="save-template" toolbar="bottom" location="after" />
<!-- Add custom element wrapping here -->
<custom-element>
<template #save-template>
<DxButton text="TEST" #click="onOk" />
</template>
</custom-element>
</slot>
</DxPopup>
</template>
More details:
https://eslint.vuejs.org/rules/valid-v-slot.html
https://vuejs.org/guide/components/slots.html#named-slots
I've found the solution on Stackoverflow:
<template>
<DxPopup
v-bind="$attrs"
:hide-on-outside-click="true"
:drag-enabled="true"
:wrapper-attr="popupAttributes"
position="center"
v-on="$listeners"
#hiding="onHiding"
>
<slot />
<slot name="footer">
<DxToolbarItem template="save-template" toolbar="bottom" location="after" />
<DxToolbarItem template="cancel-template" toolbar="bottom" location="after" />
</slot>
<template #save-template>
<DxButton text="TEST" #click="onOk" />
</template>
<template #cancel-template>
<DxButton text="Cancel" #click="onCancel" />
</template>
</DxPopup>
</template>

How to configure HeadlessUI transition to slide up from bottom in Vue.js

I am attempting to implement the HeadlessUI transition feature into my Vue.js project (https://headlessui.dev/vue/transition#basic-example). The default feature in the HeadlessUI docs is configured to rotate into view. However, I wish to configure the feature to instead slide up from the bottom of the screen. How can I go about configuring the feature to slide up?
Here is the code:
<template>
<div class="flex flex-col items-center py-16">
<div class="w-32 h-32">
<TransitionRoot
appear
:show="isShowing"
as="template"
enter="transform transition duration-[400ms]"
enter-from="opacity-0 rotate-[-120deg] scale-50"
enter-to="opacity-100 rotate-0 scale-100"
leave="transform duration-200 transition ease-in-out"
leave-from="opacity-100 rotate-0 scale-100 "
leave-to="opacity-0 scale-95 "
>
<div class="w-full h-full bg-white rounded-md shadow-lg" />
</TransitionRoot>
</div>
<button
#click="resetIsShowing"
class="flex items-center px-3 py-2 mt-8 text-sm font-medium text-white transition transform bg-black rounded-full active:bg-opacity-40 hover:scale-105 hover:bg-opacity-30 focus:outline-none bg-opacity-20"
>
<svg viewBox="0 0 20 20" fill="none" class="w-5 h-5 opacity-70">
<path
d="M14.9497 14.9498C12.2161 17.6835 7.78392 17.6835 5.05025 14.9498C2.31658 12.2162 2.31658 7.784 5.05025 5.05033C7.78392 2.31666 12.2161 2.31666 14.9497 5.05033C15.5333 5.63385 15.9922 6.29475 16.3266 7M16.9497 2L17 7H16.3266M12 7L16.3266 7"
stroke="currentColor"
stroke-width="1.5"
/>
</svg>
<span class="ml-3">Click to transition</span>
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { TransitionRoot } from '#headlessui/vue'
const isShowing = ref(true)
function resetIsShowing() {
isShowing.value = false
setTimeout(() => {
isShowing.value = true
}, 500)
}
</script>

custom navigation for q-carousel not working

I am struggling solving my navigation q-carousel that I want, it is does not work.
It just shows default navigation only but not the custom one that I grab the code from the Quasar website.
My template:
<q-card-section class="q-pa-none" >
<div style="width:60%; padding-bottom: 250px"
class="bg-transparent text-center q-gutter-y-lg absolute-center ">
<q-carousel
animated
v-model="slide"
arrows
navigation
infinite
control-type="flat"
control-color="secondary"
class="bg-transparent text-center">
>
<template v-slot:navigation-icon="{ active, btnProps, onClick }">
<q-btn v-if="active" size="lg" icon="home" color="yellow" flat round dense #click="onClick" />
<q-btn v-else size="sm" :icon="btnProps.icon" color="white" flat round dense #click="onClick" />
</template>
<q-carousel-slide :name="1" >1</q-carousel-slide>
<q-carousel-slide :name="2">2</q-carousel-slide>
<q-carousel-slide :name="3">3</q-carousel-slide>
</q-carousel>
</q-card-section>
My script:
export default {
data() {
return {
slide : 1,
}
}
}
Your code is actually working, but you kind of mixed opening and closing tags.
There is no open tag for </q-card-section>
There is no closing tag for your leading <div>
The below code should work for you:
<div
style="width: 60%; padding-bottom: 250px"
class="bg-transparent text-center q-gutter-y-lg absolute-center"
>
<q-carousel
animated
v-model="slide"
arrows
navigation
infinite
control-type="flat"
control-color="secondary"
class="bg-transparent text-center"
>
<template v-slot:navigation-icon="{ active, btnProps, onClick }">
<q-btn
v-if="active"
size="lg"
icon="home"
color="yellow"
flat
round
dense
#click="onClick"
/>
<q-btn
v-else
size="sm"
:icon="btnProps.icon"
color="white"
flat
round
dense
#click="onClick"
/>
</template>
<q-carousel-slide :name="1">1</q-carousel-slide>
<q-carousel-slide :name="2">2</q-carousel-slide>
<q-carousel-slide :name="3">3</q-carousel-slide>
</q-carousel>
</div>
You should consider setting up auto formatting in your code editor/IDE to auto format your source code, if you are using VS Code you can do this quite easily: https://stackoverflow.com/a/29973358/13765033
This way, you shouldn't run into such trouble again (it also helps Stack Overflow users to read your source code).

What is the correct way to use vue component libraries?

I am trying to use some external vue component libraries in a Laravel project but my first few attempts with vue-avatar, vue notification bell and pwa-install have all been unsuccessful.
With the first two, everything appears to check out, there're no build errors and the components actually get displayed in the html, but without the avatar or notification bell. There's no indication that the external packages where imported into my components.
These were the steps I took:
npm install of vue-avatar and notification-bell as required.
I created a component for each, imported the installed each package and did a default export.
I then utilised my component in another file as normal.
The codes are basically boilerplate with nothing to add so I'm at a loss as to why I didn't get the expected output.
Any help would be appreciated.
This is my avatar component code:
<template>
<div></div>
</template>
<script>
import Avatar from 'vue-avatar'
export default {
components: {
Avatar
}
}
</script>
And this is the code of the layout file where I used it:
<template>
<div>
<div class="min-h-screen bg-gray-100">
<nav class="bg-white border-b border-gray-100">
<!-- Primary Navigation Menu -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo -->
<div class="flex-shrink-0 flex items-center">
<inertia-link :href="route('dashboard')">
<breeze-application-logo class="block h-9 w-auto" />
</inertia-link>
</div>
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<breeze-nav-link :href="route('dashboard')" :active="route().current('dashboard')">
Dashboard
</breeze-nav-link>
</div>
</div>
<div v-if="$page.props.flash.message" class="alert">
{{ $page.props.flash.message }}
</div>
<!-- <div>
<broadcast-message></broadcast-message>
</div> -->
<avatar :username="$page.props.auth.user.first_name"></avatar>
<notification-bell />
<div class="hidden sm:flex sm:items-center sm:ml-6">
<!-- Settings Dropdown -->
<div class="ml-3 relative">
<breeze-dropdown align="right" width="48">
<template #trigger>
<span class="inline-flex rounded-md">
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
{{ $page.props.auth.user.first_name }}
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</span>
</template>
<template #content>
<breeze-dropdown-link :href="route('logout')" method="post" as="button">
Log Out
</breeze-dropdown-link>
</template>
</breeze-dropdown>
</div>
</div>
<!-- Hamburger -->
<div class="-mr-2 flex items-center sm:hidden">
<button #click="showingNavigationDropdown = ! showingNavigationDropdown" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': showingNavigationDropdown, 'inline-flex': ! showingNavigationDropdown }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! showingNavigationDropdown, 'inline-flex': showingNavigationDropdown }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': showingNavigationDropdown, 'hidden': ! showingNavigationDropdown}" class="sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<breeze-responsive-nav-link :href="route('dashboard')" :active="route().current('dashboard')">
Dashboard
</breeze-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="flex items-center px-4">
<div class="font-medium text-base text-gray-800">{{ $page.props.auth.user.first_name }}</div>
</div>
<div class="mt-3 space-y-1">
<breeze-responsive-nav-link :href="route('logout')" method="post" as="button">
Log Out
</breeze-responsive-nav-link>
</div>
</div>
</div>
</nav>
<!-- Page Heading -->
<header class="bg-white shadow" v-if="$slots.header">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<slot name="header" />
</div>
</header>
<!-- Page Content -->
<main>
<slot />
</main>
</div>
</div>
</template>
<script>
import BreezeApplicationLogo from '#/Components/ApplicationLogo'
import BreezeDropdown from '#/Components/Dropdown'
import BreezeDropdownLink from '#/Components/DropdownLink'
import BreezeNavLink from '#/Components/NavLink'
import BreezeResponsiveNavLink from '#/Components/ResponsiveNavLink'
//import BroadcastMessage from '#/Components/BroadcastMessage'
import Avatar from '#/Components/DashboardAvatar'
import NotificationBell from '#/Components/DashboardNotificationBell'
export default {
props: {
username: String,
},
components: {
BreezeApplicationLogo,
BreezeDropdown,
BreezeDropdownLink,
BreezeNavLink,
BreezeResponsiveNavLink,
//BroadcastMessage,
Avatar,
NotificationBell,
},
data() {
return {
showingNavigationDropdown: false,
}
},
}
</script>
Following your inputs, I tried to use the import in my component as suggested but I got a 'maximum call stack exceeded' error in console. See my new code:
<template>
<avatar :username="username"/>
</template>
<script>
import Avatar from 'vue-avatar'
export default {
props: {
username: String
},
name: 'DashboardAvatar',
components: {
Avatar
}
}
</script>
When I imported and used it directly, I got a type error 'cannot read property _c of undefined.
I corrected an error in my component: <avatar :username="username" /> not <dashboard-avatar> and the error is now the same type error as using the component directly that I referred to above.
I think you might misunderstand how Vue SFCs work.
You are importing the avatar component, but aren't actually using it.
A correct way would be for example:
<template>
<avatar v-bind="$attrs" v-on="$listeners"/>
</template>
<script>
import Avatar from 'vue-avatar'
export default {
name:'Avatar',
components: {
Avatar
}
}
</script>
This way you import the component from vue-avatar, and actually use it in the Avatar SFC, ($attrs and $listeners just bind all properties and events to the component). Once you have done this, your import should work.
Or you can simply import it directly in the parent component without creating a child component first (since you aren't customising the vue-avatar functionality but are just using what comes out of the box):
<script>
import BreezeApplicationLogo from '#/Components/ApplicationLogo'
import BreezeDropdown from '#/Components/Dropdown'
import BreezeDropdownLink from '#/Components/DropdownLink'
import BreezeNavLink from '#/Components/NavLink'
import BreezeResponsiveNavLink from '#/Components/ResponsiveNavLink'
//import BroadcastMessage from '#/Components/BroadcastMessage'
import Avatar from 'vue-avatar' <----------------------Use the module here directly.
import NotificationBell from '#/Components/DashboardNotificationBell'
export default {
props: {
username: String,
},
components: {
BreezeApplicationLogo,
BreezeDropdown,
BreezeDropdownLink,
BreezeNavLink,
BreezeResponsiveNavLink,
//BroadcastMessage,
Avatar,
NotificationBell,
},
...
You can use vue components directly, at least until you reach their limit and add some customization or whatever you feel like. You don't have to create a component for that component.
Your template for that component is just an empty div.
If you want to create a component for the component you should use it, not just import it. I'm a tiny bit rusty on Vue but I'm sure you can do this for the template instead:
<template>
<Avatar someAttribute="value" />
</template>
But you can just as well import the avatar component and use <Avatar> where you need it directly.
Creating a component like you did is useful for passing default parameters if you want to have some app-wide attributes you don't want to repeat. In this case you should also forward props to that component so it stays customizable for others.

How to customize bootstrap-vue dropdown menu using bootstrap-vue icon?

I am working with vue js and bootstrap-vue. I am tring to implement bootstrap vue datatables.In the table I want to use dropdownt using tree-dot-vertical icon in the action column.
Here my table view..
My table view
In the above table the iconic dropdown menu in the action column there are two icon .One is three dot vertical icon and the other is arrow sign. I want to remove the arrow sign and border from the dropdown menu.
Here the code for dropdown menu..
<template v-slot:cell(actions)="data">
<div>
<b-dropdown id="dropdown-1" variant="outline-info">
<template #button-content>
<b-icon
icon="three-dots-vertical"
aria-hidden="true"
></b-icon>
</template>
<b-dropdown-item
variant="primary"
:to="{
name: 'QuizEditPage',
params: { id: data.item.id },
}"
>Edit</b-dropdown-item
>
<b-dropdown-item
variant="danger"
#click="deleteQuiz(data.item.id)"
>Delete</b-dropdown-item
>
</b-dropdown>
</div>
</template>
How can solve the proble?Please help.
Using no-caret solves your problem.
Note that you can replace <custom-icon /> with <b-icon icon='three-dots-vertical' />
Vue.component('customIcon', {
template: `<svg xmlns="http://www.w3.org/2000/svg" width="15.352" height="15.355" viewBox="0 0 15.352 15.355">
<path id="Union_19" data-name="Union 19" d="M-19.5-15958.5l-7.5,7.5,7.5-7.5-7.5-7.5,7.5,7.5,7.5-7.5-7.5,7.5,7.5,7.5Z" transform="translate(27.176 15966.178)" fill="none" stroke="#bbb" stroke-width="0.5"/>
</svg>`
})
new Vue({
el: "#app",
});
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-dropdown no-caret>
<template #button-content>
Custom Dropdown
<custom-icon /> // or any other icons for example b-icon
</template>
<b-dropdown-item>First Action</b-dropdown-item>
<b-dropdown-item>Second Action</b-dropdown-item>
</b-dropdown>
</div>