Pass scoped slots in recursive component in Vue - vue.js

I want to implement vue component - tree. Each node doesn't know how to display itself, customer should know (see line 5). I want to setup scoped slots for parent node and for all children. But children data is not passed up to be displayed correctly from 3-rd level. Example https://codepen.io/vlapenkov/pen/gOpbxRG?editors=1011
<div id="app" class="jstree jstree-default jstree-default-medium">
<ul class="jstree-container-ul jstree-children jstree-no-icons">
<tree-item
v-for="(child, index) in treeData"
:item="child"
:is-last="treeData.length-1 === index"
:level="0"
>
<template scope="shape">
<div style="position:relative; display:inline-block;">{{ shape.name }}</div>
</template>
</tree-item>
</ul>
</div>
<template id="item-template" >
<li class="jstree-node" v-bind:class="className">
<i class="jstree-icon jstree-ocl" v-on:click="toggle"></i>
<a class="jstree-anchor" href="#" v-bind:class=" isSelected ? 'jstree-clicked':''">
<i class="jstree-icon jstree-themeicon"></i>
<span>{{item.name}}</span>
<slot v-bind="item"></slot>
</a>
<ul v-show="isOpen" class="jstree-children">
<tree-item
v-for="(child, index) in item.children"
:key="index"
:item="child"
:is-last="item.children.length-1 === index"
:level="level+1"
>
<slot v-bind="child"></slot>
</tree-item>
</ul>
</li>
</template>

You can pass through scoped slots like this:
<template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>

Related

vuedraggable working until <transition-group> added, draggable element must have an item slot

Trying out vuedraggable and the items drag and sort.
<draggable :list="listRows" item-key="listID" class="list-group">
<template #item="{ element }">
<div class="list-group-item" >
{{ element.name }}
</div>
</template>
</draggable>
This works but if I add <transition-group>:
<draggable :list="listRows" item-key="listID" class="list-group">
<transition-group>
<template #item="{ element }">
<div class="list-group-item" >
{{ element.name }}
</div>
</template>
</transition-group>
</draggable>
I get the error:
draggable element must have an item slot
I can't find any examples of how to fix this error or any explanation.

Is this the right approach to create a component?

I made a view to show some contact information for the user:
<template>
<div v-for="user in users" class="user">
<div class="userInformation">
<img :src="user.photo" />
<div class="userName">
<h3>{{ user.age }}</h3>
<p>{{ user.gender }}</p>
</div>
</div>
<div class="button-wrapper">
<a href="#">
<button #click="$router.push(`/user/${user.id}`)">User Profile</button>
</a>
</div>
</div>
</template>
<style>
</style>
users is an array that holds all users which I fetch from the backend.
I want to create a component so that I can re-use the user card in other classes and don´t have to include the markup. I tried it the following way but I'm stuck at the button to redirect the user and the img because I don´t know how to use named slots there.
<template>
<div class="user">
<div class="userInformation">
<img />
<div class="userName">
<h3>{{ age }}</h3>
<p>{{ gender }}</p>
</div>
</div>
<div class="button-wrapper">
<a href="#">
<button>User Profile</button>
</a>
</div>
</div>
</template>
<script>
export default {
name: "UserCard",
props: [
"age",
"gender"
]
};
</script>
Another problem is that I have to re-create the fetch method for my users in other classes to access the user information. Would there be a better way of doing this?
// fetch user data from backend and create users array
...
<div v-for="user in users" :key="user.name">
<UserCard
:age="`${user.age}`"
:gender="`${user.gender}`"
/>
</div>
Is this the right approach to create a reusable component?
You're headed in the right direction for your component. If you wanted a named slot for the button you could use something like this.
Child Component
<template>
...
<slot name="button">
<!-- default/fallback content can be provided, if the parent does
not provide slot content the button-wrapper div will appear -->
<div class="button-wrapper">
<a href="#">
<button>Default Button</button>
</a>
</div>
</slot>
</div>
</template>
Parent
<div v-for="user in users" :key="user.name">
<UserCard
:age="user.age"
:gender="user.gender">
<template v-slot:button>
<div>some custom button here {{ user.phone }}</div>
</template>
</UserCard>
</div>
Also compilation scope (Vuejs v2 guide) is an important thing to keep in mind with slots - "Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope."
In terms of fetching your users, that's a separate issue. Look into something like Vuex or other ways of managing shared state if you find yourself constantly having to fetch users in various components

All tab elements are active when using uk-tab with Vue.js

I am using getuikit's tab component ( https://getuikit.com/docs/tab ) in my Vue-App:
Now I see that every tab is active, if I use v-for to iterate through an array.
<ul class=" uk-tab-left" uk-tab>
<li v-for="test in tests" id="test">{{ test }}</li>
</ul>
In my codepen example you can see, that the class uk-active is always inserted automatically:
https://codepen.io/spqrinc/pen/Ydzbez
Is there a possibility to change this behavior?
You can add a empty li element before the loop to make sure the active class will not be added to the others.
Don't forget to add a key to the loop and bind the id.
<div id="app">
<div>
<div uk-grid>
<div class="uk-width-1-4#m">
<ul class=" uk-tab-left" data-uk-tab>
<li></li>
<li v-for="test in tests" :key="test" :id="test">
{{ test }}
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="app">
<div>
<div uk-grid>
<div class="uk-width-1-4#m">
<ul class=" uk-tab-left" data-uk-tab>
<template v-for="test in tests">
<li :key="test" :id="test">
{{ test }}
</li>
</template>
</ul>
</div>
</div>
</div>
</div>

How to add number or id each element in vue js?

in my case i create dynamic form (like todo app) in another components. i want accesibility for other actions. therefore i must set id or number each created element(div). when i add increment method console shows duplicate key error.
how can i add number or id each element?
For examples: this is 1. created element,
this is 2. created element,
this is 3. created element,
some codes:
methods: {
...mapActions(["setAdList"]),
ilanVer() {
this.alert = true;
let adListObj = {
adName: this.adName,
text: this.text,
province: this.province,
education: this.education,
solder: this.solder,
id: this.id
}
this.setAdList(adListObj);
this.id += 1;
console.log(this.id)
},
}
<template>
<!-- eslint-disable max-len -->
<div class="ad-box">
<h1 class="d-flex justify-content-center align-items-center mt-2">İlanlarım</h1>
<hr />
<div class="ilan-list">
<b-card :title=item.adName v-for="(item) in adList" :key="item.id" class="border border-info rounded w-50">
<b-badge class="ml-3">{{item.id}}</b-badge>
<p class="card-text">Aday Özellikleri: <span class="text-center">{{item.text}}</span> </p>
<p class="card-text">Şehir: {{item.province}}</p>
<p class="card-text">Eğitim: {{item.education}}</p>
<p class="card-text">Askerlik: {{item.solder}}</p>
<router-link to="/ilandetayi/:id">
<b-button class="btn-outline-success mr-2">İlanlarıma Git</b-button>
</router-link>
</b-card>
<hr />
</div>
</div>
</template>
You can use index when using v-for directive
In your case
v-for="(item, index) in adList" and then inside the block index will have values 0, 1, 2, ....
You can use Index item of v-for to define the unique id
v-for="(item, index) in adList" :key="index"
<template> <!-- eslint-disable max-len --> <div class="ad-box">
<h1 class="d-flex justify-content-center align-items-center mt-2">İlanlarım</h1>
<hr />
<div class="ilan-list">
<b-card :title=item.adName v-for="(item, index) in adList" :key="index" class="border border-info rounded w-50">
<b-badge class="ml-3">{{item.id}}</b-badge>
<p class="card-text">Aday Özellikleri: <span class="text-center">{{item.text}}</span> </p>
<p class="card-text">Şehir: {{item.province}}</p>
<p class="card-text">Eğitim: {{item.education}}</p>
<p class="card-text">Askerlik: {{item.solder}}</p>
<router-link to="/ilandetayi/:id">
<b-button class="btn-outline-success mr-2">İlanlarıma Git</b-button>
</router-link>
</b-card>
<hr />
</div> </div> </template
> Blockquote

vue transition groups with vue2-animate not working

I've been struggling with making vue transitions work.
I'm using vue2-animate along with vue to create some simple transition effect for when list items appear/disappear.
Here's the block:
<transition-group class="mt-2"
name="fadeLeft"
v-if="type == selectedType"
tag="ul">
<li class="mb-2" v-bind:key="category.name"
v-for="(category, index) in getCategoriesForType(type)"
#click="selectCategory(category)">
{{ category.name }}
</li>
</transition-group>
It doesn't add any effects when I try it. It simply shows/ hides the lists.
I've tested/confirmed that the animation is working in different component, but cannot figure out why the above code doesn't do any animations.
Here's the block that was working:
<ul class="list-group notes" v-if="notes.length > 0">
<transition-group name="fadeLeft">
<li v-for="(note, index) in notes" v-bind:key="note" class="list-group-item" v-on:remove="notes.splice(index, 1)">
<button class="close" #click="removeNote(index)"><span class="fa fa-times"></span></button>
{{ note.text }}
</li>
</transition-group>
</ul>