[Vuejs]-Vue: Dynamically inject property data into <component />

0👍

I could solve it via slot but I’ve still needed to use forceUpdate() in the LayoutComponent…
However with the genericProps it’s good enough for my case.

Parent Template

  <template v-slot:leftColumn >

    <div v-for="(entry, index) in firstColumn" :key="`left_${index}`" >

      <component :is="entry" :genericProps="entry.genericProps" />
    </div>
  </template>

  <template v-slot:rightColumn>

    <div v-for="(entry, index) in secondColumn" :key="`right_${index}`" >

      <component :is="entry" :genericProps="entry.genericProps" />
    </div>
  </template>

Parent Code

This code is called via mounted() or via watch when the async call from the API is finished.

  createMetadataContent() {

    let currentContent = this.currentMetadataContent;
    const components = this.$options.components;

    currentContent = this.mixinMethods_enhanceMetadataEntry(currentContent, this.cardBGImages);

    if (currentContent && currentContent.title !== undefined) {

      this.body = metaDataFactory.createBody(currentContent);
      this.$set(components.MetadataBody, 'genericProps', this.body);

      this.citation = metaDataFactory.createCitation(currentContent);
      this.$set(components.MetadataCitation, 'genericProps', this.citation);
      // a few more components and data here


      this.firstColumn = [
        components.MetadataBody,
        // a few more components here
      ];

      this.secondColumn = [
        components.MetadataCitation,
        // a few more components here
      ];

      this.singleColumn = [
        components.MetadataBody,
        components.MetadataCitation,
        // a few more components here
      ];

      this.$forceUpdate();
    }
  }

TwoColumnLayout Template

    <v-flex v-bind="firstColWidth" >

      <v-layout column>

        <slot name="leftColumn" />

      </v-layout>
    </v-flex>


    <v-flex v-if="secondColumn" v-bind="secondColWidth" >

      <v-layout column>

        <slot name="rightColumn" />

      </v-layout>
    </v-flex>

TwoColumnLayout Code

updated() {
  this.$children.forEach((child) => {
    child.$forceUpdate();
  });
},

Child Code

All child components have the genericProps object which is accessed via mixin method

    props: {
      genericProps: Object,
    },
    computed: {
      title() {
        return this.mixinMethods_getGenericProp('title');
      },
      id() {
        return this.mixinMethods_getGenericProp('id');
      },
      description() {
        return this.mixinMethods_getGenericProp('description');
      },
    }

Mixin method

    mixinMethods_getGenericProp(propName) {
      return this.genericProps[propName] ? this.genericProps[propName] : null;
    },

0👍

I once had a similar situation where I had a dynamic <compnonent :is="currentComponent"> and solved it by storing a ‘childPayload’-attribute to my data and passed it as prop to the children. Whenever my payload changed, it got refreshed in the children.

<template>
    <div>
        <div class="btn btn-primary" @click="changePayload">Change Payload</div>
        <component :is="isWhat" :payload="payload"></component>
    </div>
</template>

<script>
    export default {
        name: "Test",
        data() {
            return {
                isWhat: 'div',
                payload: { any: 'data', you: 'want', to: 'pass'}
            }
        },
        methods: {
            changePayload() { // any method or api call can change the data
                this.payload = { some: 'changed', data: 'here' }
            }
        }
    }
</script>

Leave a comment