Dynamically loading child components in parent component - javascript

I am a beginner in Vue.js so please bear with me. I created two child components and one parent component. I am able to load both the components in the parent components. Now, one of my child component should load in the parent component by default. It will have a link, and when clicked, it should load the other child component within the same parent component, by passing and ID value from itself to the loading component. Below is my code.
Parent component (App.vue):
<template>
<div id="app">
<body>
<main>
<div class="main-body">
<component v-bind:is="currentComp">
</component>
</div>
</main>
</body>
</div>
</template>
<script>
import HomeContent from './components/HomeContent.vue';
import DetailContent from './components/DetailContent.vue';
import { changeRoute } from './main.js';
export default {
name: 'app',
data() {
return {
currentComp: 'HomeContent'
};
},
components: {
HomeContent, //this is the default child component
DetailContent, //this is the other child component which should get loaded dynamically
},
created() {
changeRoute.$on('switchComp', comp => {
this.currentComp = comp;
})
}
}
</script>
Default child component (HomeContent.vue):
<template>
<div>
This is Default child component
Click to load the other child dynamically
</div>
</template>
<script>
import { changeRoute } from '../main.js';
export default {
name: 'HomeContent',
props: {
msg: String
},
methods: {
switchComponent(comp) {
changeRoute.$emit('switchComp', comp);
}
}
}
</script>
The other child component (DetailContent):
<template>
<div>
This is the other loaded child component.
</div>
</template>
<script>
export default {
name: 'DetailContent',
props: {
msg: String
},
mounted(){
alert('mount ok');
}
}
</script>
With the above approach DetailContent get loaded on click of a link from the HomeContent. Now, how can pass some data (e.g. ID = 1) from HomeContent to DetailContent. Any help with this please?

Related

Vue js pass a function from child chile to another child component on a click event

I am trying to pass a function when a button is clicked, the button is clicked in a child element, then passed through a parent element to another child component, and i dont want to use the store for that, How can i do that?
components/footer/footer.vue
-- This is where the button is clicked
<template>
<div class="footer-bottom-header-menu-bar mob" #click="showMenu">
<img src="~/assets/svg/menubar.svg" alt="+" />
</div>
</template>
<script>
export default {
methods: {
showMenu() {
this.$emit("show-menu");
}
}
}
</script>
layouts/default.vue
--This is the parent component where that receives the click function and is to pass it into the app-header
<template>
<div>
<app-header />
<Nuxt />
<app-footer #show-menu="showMenu()"/>
</div>
</template>
<script>
import header from "~/components/header/header";
import footer from "~/components/footer/footer";
export default {
components: {
'app-header': header,
'app-footer': footer
},
methods: {
showMenu() {
console.log("clicked");
}
}
}
</script>
components/header/header.vue
-- I want the click function to perform an action inside this component
<script>
export default {
data() {
return {
showMenuBar: false
}
},
}
</script>
Why are you worried about passing a function around?
When you emit the show-menu event simply toggle a piece of data in your parent component like this:
<template>
<div>
<app-header :showMenuBar="showMenuBar" />
<Nuxt />
<app-footer #show-menu="showMenu"/>
</div>
</template>
<script>
import header from "~/components/header/header";
import footer from "~/components/footer/footer";
export default {
components: {
'app-header': header,
'app-footer': footer
},
data() {
return {
showMenuBar: false;
};
},
methods: {
showMenu() {
// I would make this more dynamic than always
// hardcoding it to true, but you get the idea
this.showMenuBar = true;
}
}
}
</script>
Then in your AppHeader simply take it in as a prop:
<script>
export default {
props: {
showMenuBar: {
type: Boolean,
default: false,
},
}
</script>
You can declare any attribut on your parent component:
data() {
return { toBeWatched: 0 };
}
Then pass it like a props from the parent to the header child:
<app-header :Trigger="toBeWatched" />
When you listen to the #show-menu event (comming from footer child),
make any change on your attribut:
<app-footer #show-menu="toBeWatched++" />
Finally you can watch for this change on your header child and
trigger your function.
<script>
export default {
data() {
return {
showMenuBar: false
};
},
props: ['Trigger'],
watch: {
Trigger() {
this.showMenuBar = !this.showMenuBar; // or do whatever you want
console.log('showMenuBar : ' + this.showMenuBar);
}
}
};
</script>

Vue communcation between child to parent to another child

I got a <payment-child-component> which handles all the subscriptions and payments, i also have
another <check-active-child-component>
I want these two components to communicate. persay in the <payment-component> a user cancel's his subscription i want to fire a method i have in <check-active-component> which called checkActive()
So from payment-component emits to parent-component when the subscription cancel method is triggered and then fires the checkActive() method inside check-active-component
So if my logic is good, the exact question is: how do i fire a method from parent to child component?
To call a method of a child component from its parent, you can use ref. Here is an example:
Child Component:
export default {
name: "ChildComponent",
methods: {
childMethod(){
console.log("hello from child");
}
}
};
Parent Component:
<template>
<div id="app">
<ChildComponent ref="myChild"/>
</div>
</template>
<script>
import ChildComponent from "./components/ChildComponent";
export default {
name: "App",
components: {
ChildComponent
},
mounted(){
this.$refs.myChild.childMethod()
}
};
</script>
This one is what I am using on my app.
Parent.vue
<template>
<a #click="run">Click me to execute method from child</a>
</template>
<script>
export default {
name:"parent",
methods: {
run() {
this.$root.$refs.child.methodtoexecute();
}
}
}
</script>
Child.vue
<script>
export default {
name:"child",
created() {
this.$root.$refs.child = this;
},
methods: {
methodtoexecute() {
alert("hello from child");
}
}
}
</script>

How to test for the existence of an HTML element within a Vue child component using Vue Test Utils?

It's pretty clear on how to test for the existence of a child component using Vue Test Utils through the official docs.
However, it's unclear how to test for the existence of a HTML element within that child element.
Say I have the following Child component.
<template>
<div>Child<span>Random</span></div>
</template>
<script>
export default {
name: "Child"
}
</script>
And I have the following Parent component.
<template>
<div>
<span v-show="showSpan">
Parent Component
</span>
<Child v-if="showChild" />
</div>
</template>
<script>
import Child from "./Child.vue"
export default {
name: "Parent",
components: { Child },
data() {
return {
showSpan: false,
showChild: false
}
}
}
</script>
The following snippet would be how I would find the existence of the child component.
it("renders a Child component", () => {
const wrapper = shallowMount(Parent, {
data() {
return { showChild: true }
}
})
expect(wrapper.find({ name: "Child" }).exists()).toBe(true)
})
However, my question is, how would I assert the existence of <span>Random</span> if I wanted to?

How to pass an imported component through props?

Is there a way I can pass a component through props to a child component from the parent without having to import it from the child?
Parent component:
<template>
<ChildComponent :component="componentName">
</template>
<script>
import componentName from '#/components/componentName.vue'
</script>
Child component:
<template>
<div>
<component :is="component">
</div>
</template>
<script>
props: {
component: Object
}
</script>
Currently, in this setup, I am getting Unknown custom event Did you register the component correctly? Error. I know it wants me to register the component in the child component but I don't want to have to import the component from the child. Is there a way to pass the import to the child through props? Is this not possible?
You are really close, the issue is in your first template:
<template>
<ChildComponent :component="componentName">
</template>
<script>
// this is not available in template scope
import componentName from '#/components/componentName.vue'
export default {
data: {
// this, however, is available!
componentName
}
}
</script>
You are mising export default.
parent.vue:
<template>
<ChildComponent :component="componentName">
</template>
<script>
import componentName from '#/components/componentName.vue'
export default {
data() {
return {
componentName
}
},
}
</script>
child.vue:
<template>
<div>
<component :is="component">
</div>
</template>
<script>
export default {
props: {
component: Object
},
}
</script>

Call a function in imported child component on click from a parent element?

Is it possible to call a function in an imported component from "parent element"? Because I have a few modules that I wanna have in my app and show them dynamically in my app. I though if I import a component like Header in my main App.vue folder it will recognize the function from the main App.vue folder.
Example of App.vue:
<template>
<div>
<div class="m-grid m-grid--hor m-grid--root m-page">
<!-- <loader></loader> -->
<mobile-menu-partial></mobile-menu-partial>
<header-partial></header-partial>
<div :is="currentComponent"></div>
<div v-show="!currentComponent" v-for="component in componentsArray" :key="component.id">
<button #click="swapComponent(component)">{{component}}</button>
</div>
<button #click="swapComponent(null)">Close</button>
<footer-partial></footer-partial>
</div>
</div>
</template>
<script>
import Loader from '#/components/partials/Loader.vue'
import MobileMenu from '#/components/partials/MobileMenu.vue'
import Header from '#/components/partials/Header.vue'
import Footer from '#/components/partials/Footer.vue'
export default {
data () {
return {
currentComponent: null,
componentsArray: ['dashboard', 'schedule', 'locations', 'mileage']
}
},
name: 'App',
components: {
'loader': Loader,
'mobile-menu-partial': MobileMenu,
'header-partial': Header,
'footer-partial': Footer
},
methods: {
swapComponent: function (component) {
console.log('component', component)
this.currentComponent = component
if (component === null) {
console.log('anywhere_main')
this.$router.push('/')
} else {
this.$router.push('/' + component)
}
}
}
}
</script>
<style>
</style>
So can I have access of the function swapComponent in my header-partial? Because there are my modules for opening.
Calling child component's method from parent component
Say you have a child-comp component and want to call its childMethod method from the parent.
Use ref="someVariableName" on the parent's template and this.$refs.someVariableName on the parent's JavaScript.
Parent's template:
<div id="app>
<child-comp ref="myChild"></child-comp>
<button #click="callChildMethod">GO</button>
</div>
Parent's JavaScript code:
{
data: // ...
// ...
methods: {
callChildMethod: function () {
this.$refs.myChild.childMethod();
}
}
Calling parent's method from child
Emit an event in <child-comp> and listen to it in parent.
Parent's template (listening to an event):
<div id="app>
<child-comp #eventname="parentsMethod"></child-comp>
</div>
Notice that #eventname="parentsMethod" is the same as v-on:eventname="parentsMethod".
Parent's JavaScript code:
{
data: // ...
// ...
methods: {
parentsMethod: function (event) {
console.log('parent called', event);
}
}
Child's JavaScript code:
{
data: // ...
// ...
methods: {
someChildMethod: function () {
this.$emit('eventname', {some: 'object value'});
}
}
Now whenever, at the child, you call someChildMethod it will trigger the event and, since the parent is listening to it, it will execute parentsMethod in the parent.

Categories

Resources