How to get all the props that a parent component has inside a child component In vue js? - vue.js

How to get all the props like $store, $parent, $root everything that a parent component has inside a child component?
So I'm creating a parent component and a child.
However I don't have anything to render within the child. So I'm creating a renderless child component.
However I'm programatically inserting new html elements via child component
following piece of code is the parent component where I mount the child component.
This is the method I found online.
This is working fine. But I'm not getting the props like this.$store , this.$parent and all (which are automatically available inside the parent component) in the child component.
import { Child } from "./components/child";
export default {
name: "parent",
components: {},
props: [],
data() {
return {};
},
computed: {},
created() {
new Child().$mount();
},
mounted() {},
methods: {},
};
This is the child component.
import Vue from "vue";
const CHILD = {
name: "child",
components: {},
props: [],
data() {
return {};
},
render() {
return;
},
computed: {},
created() {},
mounted() {},
methods: {},
};
export const Child = Vue.extend(CHILD);
So the basic idea is to create child component classes having all the options like $store $el and all (everything vue provides).... but instead of instantiating it inside the template I want to instantiate them in the parent component like this: new Child({...props}).
So is that possible. I'm doing this because my child components are renderless. (But within the child components I'm creating Dom elements..., & the reason I want to extend all the functionalities provided by vue is because in that way I don't want to write my own store, my own event emitter, my own prop binder.... everything will be automatically available...)
KEY TAKEAWAY is that I want to create Child components manually like by calling new Child() rather than registering them as components inside the parent as components: {'app-child': Child} and instantiating them inside the parent template ... Along with that I want every functionalities provided by vue inside the child component.. something like extending vue..
Also How can I listen to events from the child created as above ...
something like this.
// child
created() {
this.$emit('event')
}
//parent
mounted() {
this.child.$on('event', console.log)
}
sources:
https://css-tricks.com/creating-vue-js-component-instances-programmatically/
https://css-tricks.com/building-renderless-vue-components/

Related

Trigger child function in parent component

I have a component Base.vue with a child Component that is being displayed by router-view. In the child component I have a function in my setup(), but I want the function to be triggered by menu item in Base.vue. How can I achieve this in vue 3? I can't use vuex for this, because the function uses a lot of google map things and refs.
Base.vue router-view Component <- component contains another component which I need to use the function from in Base.vue
This can be easily implemented through the Vue Composition Api
Assign a ref to your child component as such
<child-component ref="childRef"></child-component>
Declare the ref in your setup function as
import { ref } from 'vue'
export default {
components: { },
props: {},
setup(context,props) {
const childRef = ref(null)
return {childRef}
}
}
You can now call functions in your child component by leveraging your childRef, inside the setup function childRef.value.childFunction() can call functions declared in your child component

Vuejs copy dynamic components methods

I am trying to make a visual representation of a component library. I am using dynamic <component>s to render each component. However, as I am populating the component with its slots, I am running into issues due to parent methods missing.
I want the components to be usable (demo) therefore I need to compensate for this.$parent not working.
<template>
<component v-bind:is="'s-' + comp.name" v-bind="props" ref="comp"> <!-- this is the corrent parent-->
<div v-if="comp.slots">
<div
v-for="(slot, i) in comp.slots"
v-bind:key="i"
v-bind:slot="slot.name"
>
<div v-if="slot.type == 'component'"> <!-- childs parent -->
<de-mo v-bind:comp="slot" /> <!-- this is the child calling a method on the parent -->
</div>
<div v-html="slot.value" v-else></div>
</div>
</div>
</component>
</template>
<script>
export default {
name: 'deMo',
computed: {
props() {
if (this.comp.props) {
return this.comp.props.reduce((a, r) => {
a[r.name] = r.value
return a
}, {})
}
}
},
props: {
comp: {
type: Object,
required: true
}
},
methods: this.$ref.comp.methods, //<-- this is an error
mounted(){
console.log(this.$ref.comp.methods)
}
},
</script>
<style></style>
1) Is there a way to copy the methods from the parent into this "demo" component via the ref attr
2) Alternatively, is there a better method to produce the same results?
Thanks
you can try to spread parent methods in a beforeCreate lifecycle as at this point your parent will be created and your component is going to register its all methods,
beforeCreate() {
this.$options.methods = { ...this.$parent.$options.methods };
},
however you can not access any refs in this as refs are only registered after mount of the component.
Note: Any library should use provide and inject to communicate with their component instead of referencing the parent component directly.
You can use an Event bus to communicate between components that aren't directly related to each other. Also, this is the recommended way of communication from child to parent in Vue.
bus.js
import Vue from 'vue'
export default new Vue()
demo.vue // child component that wants to call a method in the parent
import Bus from './bus.js'
export default {
mounted () {
// [1] child component will emit an event in the bus when it want to call a method of parent
Bus.$emit('invoke-parent-fn', 'param')
}
}
parent.vue // parent component where you want to render other components dynamically
import Bus from './bus.js'
export default {
methods: {
fn (param) {
console.log('// do something ' + param)
}
},
mounted () {
// [2] parent will be listening to the bus event, when child will emit an event, the handler passed in to the listener will be invoked
// [3] invoke the required method in the handler
Bus.$on('invoke-parent-fn', param => this.fn(param))
}
}

Vue.js child component not updated

I have 3 vue.js nested components: main, parent, child.
The parent component load basic data, the child is a simple countdown widget which needs just a data to be configured.
If I set the parent script with static data (IE deadline='2019-12-12') the child show the widget working nice, but if I use dynamic data it generate error.
I'm using computed to pass data to the child component and if I debug it using an alert I see 2 alerts: undefined and then the correct date.
The issue is the first computed data (undefined) crash the widget, so how to create child component using updated (loaded) data?
Parent template:
<template>
<div>
<flip-countdown :deadline=deadline></flip-countdown>
</div>
</template>
Parent Script: it needs to be fixed
export default {
components: {FlipCountdown},
props: ['event'],
computed: {
deadline: function () {
if (typeof(this.event.date)!="undefined") {
//alert(this.event.date)
return this.event.date;
} else {
return "2019-05-21 00:00:00";
}
},
},
Child template: it works
<template>
<div>
<flip-countdown :deadline="deadline"></flip-countdown>
</div>
</template>
Your parent component passes the deadline to its child component before the mounted lifecycle hook fires. Your child component sets its deadline with the initial value of undefined.
You should make deadline a computed property in child component:
computed: {
internalDeadline() {
return this.deadline; // comming from props
}
}
Then you can use internalDeadline in child.
Alternatively, you could wait to render the child component until deadline is defined:
<flip-countdown v-if="deadline !== undefined" :deadline="deadline"></flip-countdown>

vuejs-parent and child components

I am new in vuejs and Iam coding in laravel
I have watched vuejs tutorial but I have got a little confused
about parent and child components because when I started coding in laravel I just used a simple component and use it in blade and
I didn't feel needing parent component I want the usage and when to use
parent component because there were lots of documention for parent and child component I dont know when to use them.
parent component and child component is not the same, child component feeding by the parent as the prop, you can mutate data to child component by parent and emit data from child to parent for changed the prop.
for example:
////parent.vue////
<parent-component>
<child-component :item="items" :profile="profile"></child-component>
</parent-component>
export default {
data(){
items: {
id: 0,
name: 'Negar'
},
data2: {
id: 1,
name: 'Hozhabr^_^'
}
},
profile: {
url: 'http://www.alibaba.com',
company: 'alibaba',
city: 'Tehran'
}
}
//// child.vue /////
<template>
Item: {{items}}
profile: {{profile}}
</template>
export default {
props:['items', 'profile']
}

vuejs child component lifecycle diffrence root component?

this is my template
<parent>
<child></child>
</parent>
and this is child component script
beforeCreate(){
console.log('beforeCreate');
}
created(){
console.log('created');
}
beforeMount(){
console.log('beforeMount');
}
i test vuejs component lifecycle.
so i write all hook method in child component,
but created hook method in child is not called
is it normal or not??
thanks
It should work normally as other lifecycle methods. I've retested your case (based on vue cli webpack template) and it's working fine. Are you using vue-cli or custom bundle / build way?
Please, see my example below (I guess you miss comma after lifecycle method curly bracket):
<script>
// PARENT component
import Child from './components/Child'
export default {
name: 'parent',
components: {
Child
}
}
</script>
<script>
// CHILD component
export default {
name: 'child',
beforeMount () {
console.log('before mount')
},
created () {
console.log('created')
},
beforeCreate () {
console.log('before create')
}
}
</script>