mudale
mudale

Reputation: 168

how can i pass a component with props from method to dynamic components in vue?

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

Answers (1)

Leonardo Bezerra
Leonardo Bezerra

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

Related Questions