How to get refs element in scoped slot - vue.js

If there are some refs in slot's template, how can I access these refs from the component? For example:
v-component.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
created() {
console.log(this.$refs.ele)
}
}
</script>
app.vue
<template>
<v-component>
<template slot-scope="props">
<h1 ref="ele"></h1>
</template>
</v-component>
</template>
<script>
import VComponent from './v-component
export default {
components: { VComponent }
}
</script>
this.$refs.ele in v-compoent.vue output undefined. My question is how can I get this element?

Each element in named slot and scopedSlot has context.$refs.
Do not forget to check if object exists first.
<template>
<v-component>
<template slot-scope="props">
<h1 ref="ele">{{ props }}</h1>
</template>
</v-component>
</template>
<script>
import VComponent from './v-component'
export default {
components: { VComponent }
}
</script>
and
<template>
<div>
<slot demo="foo"></slot>
</div>
</template>
<script>
export default {
created() {
this.$nextTick(function() { // lazy
console.warn(this.$scopedSlots.default()[0].context.$refs)
});
}
}
</script>
Result:

This is considered as a bad idea by Vue developers: https://github.com/vuejs/vue/issues/7661
Btw, in my case in Vue3, the el entries of my slots retrieved by
this.$refs.myRef.$slots['my-slot']().el
is always null (as appContext)

On Vue 2 you can do this on mounted
mounted() {
console.log(this.$slots)
},
with more precision
You can do this
mounted() {
console.log(this.$slots.name_of_your_slot)
},

Related

Vue.JS - Avoid re-rendering of slots when parent re-renders

I'm struggling on Vue.JS with a component that has as children/slots some "complex" components with canvas data (e.g. Maps).
I want to avoid that when the parent component re-renders, their inner slots re-render. Because of how this components work (or any other scenario), every time it re-renders it needs to do all of it's "loading" steps. Even when saving their real-time state.
For example:
Component.vue
<template>
<div>
<span>{{value}}</span>
<slot></slot>
</div>
</template>
View
<Component v-model="value">
<Map :latitude="0" :longitude="0"/>
</Component>
<script>
this.value = "Hello";
setTimeout(()=>{
this.value="Hello world!";
},1000);
</script>
Is there any way to prevent from slots from re-rendering when their parent re-renders?
Thanks in advance.
Hello use props for a child component, and this child is not will rerender
App
<template>
<div id="app">
<HelloWorld msg="Hello Vue in CodeSandbox!" :somedata="key">
slot information key: {{ key }}
</HelloWorld>
<button #click="key++">key++</button>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld,
},
data() {
return {
key: 0,
};
},
};
</script>
Child
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h3>somedata from props: {{ somedata }}</h3>
<hr />
<slot></slot>
<hr />
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: {
type: String,
default: "",
},
somedata: {
type: Number,
default: 999,
},
},
created() {
console.log("renred");
},
};
</script>
How you can see I used console.log("renred"); in the child component, you can check the console, the information will be shown only one time.
https://codesandbox.io/s/naughty-platform-ib68g?file=/src/components/HelloWorld.vue

How pass data from parent to child in NuxtJS

i wonder how passing some string or dynamic data from parent to child in NuxtJs
how i tried it and not worked:
it's my parent component:
<template>
<div>
<ChildComponent :someData="Some String" />
</div>
</template>
<script>
import ChildComponent from "~/components/childComponent.vue";
export default {
components: {
ChildComponent,
},
}
</script>
and here is my ChildComponent
<template>
<div>
{{someData}}
</div>
</template>
<script>
export default {
name:"ChildComponent",
props: {
someData: String
}
}
</script>
and this method nothing rendered in ChildComponent
You don't have to bind if you are passing values directly, ie, no need of semicolon.
<ChildComponent someData="Some String" />
You only need to bind if you are passing data.
<template>
<div>
<ChildComponent :someData="localData" />
</div>
</template>
<script>
import ChildComponent from "~/components/childComponent.vue";
export default {
components: {
ChildComponent,
},
data(){
return {
localData: "Some String"
}
}
}
</script>

Vuetable2 slot in slot

I use vue(2.6.10) an Im trying to build a universal table with vuetable2 (2.0.0-beta.4).
I created a component for the general methods of vuetable.
I tried to place my "MyCustomTemplate" in the slot section of the "MyVueTable", but I got no error and nothing is shown.
My goal is to use the "MyVueTable" in other vue pages and replace the "MyCustomTemplate".
I have currently 3 entries in my data but in the List.vue component nothing is shown
List.vue
<template>
<MyVueTable :data="data" :fields="fields">
<MyCustomTemplate v-slot="vueTableTemplateSlot"/>
</MyVueTable>
</template
<script>
export default {
name:"List",
data(){
return{
data: [],
fields: [
{
name: 'vueTableTemplateSlot'
}
]
};
}
}
</script>
MyVueTable.vue
<template>
<vuetable ref="vuetable">
<slot name="vueTableTemplateSlot" slot-scope="props"/>
</vuetable>
</template>
<script>
export default {
name: 'MyVueTable',
props: ['data', 'fields'],
methods:{
//vuetable methods
}
}
</script>
MyCustomTemplate.vue
<template>
<div>
{{rowData.id}}
</div>
</template>
<script>
export default {
name: 'MyCustomTemplate',
data(){
return{
rowData: null
}
}
</script>
You can test to put your component(in List.vue) in a div or a template that will be the slot content :
<template #nameOfYourSlot>
<NameOfYourComponent>
</template>
This was answered in the official repository, you need to do this to be your custom global component: https://github.com/ratiw/vuetable-2-tutorial/wiki/lesson-17

How to access parents data value in vuejs with the template syntax

In my VueJS app I am using bootstrap-vue and want to use iframe inside a collapsable elements b-collapse. Because of some problems with iframe content and resizing (problem not related here) I found out that if I enable/disable b-embed with conditional rendering it works.
The parent component b-collapse has a data element called show which change its state if toggle is clicked. In my HelloWorld component I want that b-collapse can pass it's show value into the if check of b-embed.
My approach with this.$parent.$data.show isn't working and I am not sure if there is any better way to do so.
<template>
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { Prop, Component, Inject } from "vue-property-decorator";
#Component
export default class HelloWorld extends Vue {
src = "http://localhost:7681/";
}
</script>
Like this:
parent.vue
<template>
<Child :show="myShow"></Child>
</template>
<script>
import Child from './child'
export default {
data () {
return {
myShow: 'StackOverflow'
}
},
components: {Child}
}
</script>
child.vue
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
<script>
export default {
props: {
show: {
type: Number,
require: true
}
}
}
</script>
Or use vuex to do this.

Global check user Logged In - NuxtJS

I config a global check user if LoggedIn or not to rendering components in NuxtJS but I cant do it. Please help me.
I write computed to wrapper components (layouts/default.vue)
~/layouts/default.vue
<template>
<router-view></router-view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
computed: {
...mapGetters({
LoggedIn: 'authUser'
})
}
}
}
</script>
But I cant use it on children components / pages.
~/pages/index.vue
<template>
<div class="index-page">
<div class="" v-if="LoggedIn">
asdasd
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.LoggedIn)
// Result: Undefined
}
}
</script>