Reputation: 168
The idea is simple. To move a whole ready component with props from App to Header, but through a method. I tried all the combination of with parenthesis/without etc.. but nothing seem to work.. is it possible?
App component:
<template>
<Header
@toggleAddTask="toggleAddTask"
:showAddTask="isShowAddTask"
title="Task Tracker"
func="func"
/>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import Button from "../src/components/Button.vue";
// import state from './router/index'
export default {
name: "App",
components: {
Header,
Footer,
},
methods: {
func() {
return <Button text="i'm a button" color="red" />;
},
},
};
</script>
Header component:
<template>
<header>
<component v-bind:is="func"></component>
</header>
</template>
<script>
import Button from "./Button.vue";
export default {
name: "Header",
props: ["title", "showAddTask", "func"],
components: {
Button,
},
};
</script>
Upvotes: 0
Views: 616
Reputation: 745
You could instead of sending props, just decouple the data like so
<template>
<Header
@toggleAddTask="toggleAddTask"
:showAddTask="isShowAddTask"
:dynamic-component="dynamicComponentData"
title="Task Tracker"
/>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import Button from "../src/components/Button.vue";
export default {
name: "App",
components: {
Header,
Footer,
},
methods: {
dynamicComponentData() {
return {
component: Button,
props: {
text: "I'm a button",
color: "red"
}
}
},
},
};
</script>
With the header like this
<template>
<header>
<component
:is="dynamicComponent.component"
:text="dynamicComponent.props.text"
:color="dynamicComponent.props.color"
/>
</header>
</template>
<script>
export default {
name: "Header",
props: ["title", "showAddTask", "dynamic-component"],
};
</script>
But keep in mind, a better solution for this case would be using slots instead of injecting components.
<template>
<Header
@toggleAddTask="toggleAddTask"
:showAddTask="isShowAddTask"
title="Task Tracker">
<Button text="I'm a button" color="red"/>
</Header>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import Button from "../src/components/Button.vue";
export default {
name: "App",
components: {
Header,
Footer,
},
};
</script>
And you Header
component should have a slot like this
<template>
<header>
<slot />
</header>
</template>
<script>
export default {
name: "Header",
};
</script>
As you asked, this could be a form of adaptor
<template>
<header>
<div class="typeButtons" v-if="componentType.button">
<component
v-text="dynamicProps.text"
:is="dynamicComponent.component"
:text="dynamicProps.textType"
:color="dynamicProps.color"
/>
</div>
<div class="typeInput" v-else-if="componentType.input">
<component
:is="dynamicComponent.component"
:label="dynamicProps.text"
:rules="dynamicProps.rules"
/>
</div>
</header>
</template>
<script>
export default {
name: "Header",
props: ["title", "showAddTask", "dynamic-component"],
computed: {
componentType() {
return {
button:
dynamicComponent.type === "typeOne" ||
dynamicComponent.type === "typeTwo",
input: dynamicComponent.type === "typeThree",
};
},
dynamicProps() {
switch (this.dynamicComponent.type) {
case "typeOne":
return {
text: "Create",
textType: false,
color: "success",
};
case "typeTwo":
return {
text: "Cancel",
textType: true,
color: "error",
};
case "typeThree":
return {
text: "Cancel",
rules: [(v) => Boolean(v)],
};
default:
return { ...this.dynamicComponent.props };
}
},
},
};
</script>
Upvotes: 1