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

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

Related

How to send a data parameter to a component?

I have one component that takes a string as input. In one of its instances, I'm sending it a string literal; and to the other one, I want to send a data parameter. How can I achieve this?
App.vue
<template>
<div>
<HelloWorld msg="What's up, man?" />
<HelloWorld msg="{{message}}" />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
data() {
return {
message: "Nothing much, doing OK"
}
},
components: {
HelloWorld
}
};
</script>
HelloWorld
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
}
};
</script>
This is what I get as a result:
Any ideas? Where am I going wrong? I have looked at similar questions, but I couldn't find anything concrete.
The v-bind directive is used to bind data properties:
<HelloWorld v-bind:msg="message" />
<!-- OR shorthand -->
<HelloWorld :msg="message" />
demo

Vue - Unable pass specific value to higher component

I am getting the following - Cannot read property 'free' of undefined.
I will be adding this button component on multiple pages and I have data object which will allow me to add text based on whatever page I want displayed on a page. For example if its on the homepage I would like to use <buttons :text="buttonText.free" /> and on about us page I would like to use <buttons :text="buttonText.spend" />
Template file
<template>
<main class="container">
<buttons :text="buttonText.free" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
components: {
Buttons
}
}
</script>
Component file
<template>
<div>
<button class="button"">
<span>{{ buttonText }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
},
data () {
return {
buttonText: {
free: 'free',
spend: 'spend',
now: 'now',
nowFree: 'now free'
}
}
}
}
</script>
Could you tell me what I am doing wrong?
You should define your data in your parent component's data property. All the variables that is used inside the template tag will be fetched from data, computed or props of the component. You are passing an undefined buttonText data to your buttons component.
<template>
<main class="container">
<buttons :text="buttonText.free" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
data() {
return {
buttonText: {
free: 'free',
spend: 'spend',
now: 'now',
nowFree: 'now free'
}
}
},
components: {
Buttons
}
}
</script>
and in your buttons component, just accept the props passed by the parent component. In this case, you are using text as the props of the buttons component.
<template>
<div>
<button class="button"">
<span>{{ text }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
}
}
</script>
template.vue
<template>
<main class="container">
<buttons :text="your customized text" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
components: {
Buttons
}
}
</script>
buttons.vue
<template>
<div>
<button class="button">
<span>{{ text }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
}
}
</script>
here is a simple solution to solve your problem
but you need to learn more fundamentals on vue components
vue component doc

Vue.js - Emit from grandchild slot component didn't bubble $emit event to parent

I planned and made a modal and then created a button to close the modal window.
I wanted to change the value of isHomeDialog using $emit as an event of the button.
However, $emit's event was not delivered to "Home.vue"
Home.vue
<template>
<div>
<ReviewDialog
:is-open="isHomeDialog"
#close="closeEvent()/>
</div>
</template>
<script>
import ReviewDialog from '#/components/popup/dialog/ReviewDialog';
</script>
export default {
name: 'Home',
components: {
ReviewDialog
},
data () {
return {
isHomeDialog: true
};
},
methods: {
closeEvent () {
console.log('close');
isHomeDialog = false;
}
}
};
BaseDialog.vue
<template>
<div v-show="isOpen">
<div class="mask"> </div>
<div class="content">
<button
class="close"
#click="$emit('close')"> </button>
<slot/>
</div>
</div>
</template>
<script>
export default {
props: {
isOpen: {
type: Boolean,
required: true
}
}
};
Reviewdialog.vue
<template>
<BaseDialog
url="#/components/popup/dialog/BaseDialog"
id="review-dialog"
:is-open="isOpen"
:header-text="'REVIEW'">
<div class="warp">
<p>
test
</p>
</div>
</BaseDialog>
</template>
<script>
import BaseDialog from '#/components/popup/dialog/BaseDialog';
export default {
components: {
BaseDialog
},
props: {
isOpen: {
type: Boolean,
default: false
}
}
</script>
Home
└ BaseDialog
 └ ReviewDialog
In the above structure, I tried to send a request to BaseDialog and ReviewDialog with $emit, but it was not delivered to Home.
Is there any way to send $ emit to its parent component other than requesting it with $root.$emit?
BaseDialog emits the close event to its parent, ReviewDialog, which is not listening for it. So you need to listen in ReviewDialog, and re-emit the event to Home:
<BaseDialog
url="#/components/popup/dialog/BaseDialog"
id="review-dialog"
:is-open="isOpen"
:header-text="'REVIEW'"
#close="$emit('close')"> <-- This line is new -->
Another way to do this is to have ReviewDialog pass all its listeners down:
<BaseDialog
url="#/components/popup/dialog/BaseDialog"
id="review-dialog"
:is-open="isOpen"
:header-text="'REVIEW'"
v-on="$listeners"> <-- This line is new -->
Since two-way binding is deprecated in Vue2 + child cannot mutate props directly
Likely another approach custom component with v-model
I put reference below:
vuejs update parent data from child component

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 use children path in Vue.Js

This code
index.js
{
path: '/test',
name: 'test',
component: Test,
children: [{
path: 'p1',
name: 'p1',
component: P1
}]
}
in Component Test
test.vue
<template>
<div>
<h1>Test</h1>
<button v-on:click="navigateTo('/test/p1')">p1</button>
</div>
</template>
<script>
export default {
methods: {
navigateTo(route) {
this.$router.push(route)
}
}
}
</script>
in Component P1
<template>
<div>
<h1>P1</h1>
</div>
</template>
When i click button p1 i has path in browser but not load component p1. why??
I'm new in vue.js
I think you missed the <router-view></router-view> in your parent template (in test.vue). Router view is where the child component gets rendered. i.e.
<template>
<div>
<h1>Test</h1>
<button v-on:click="navigateTo('/test/p1')">p1</button>
<router-view></router-view>
</div>
</template>