Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically rendering child components in Vue.js v2

I'm building a faceted search system in VueJS. The general idea is simple:

A FilterGroup component contains the overall filter logic. This component accepts a variety of child components, e.g. AttributeXYZFilter. These child components are responsible for providing conditions which FilterGroup will use to filter a collection of items.

An example usage of this system looks like this:

<template>
  <FilterGroup :items="items">
    <ABCFilter/>
    <XYZFilter/>
    <AnotherFilter/>
  </FilterGroup>
</template>

My problem is as follows:

The filter components should be rendered by FilterGroup in a specific layout. Also, FilterGroup should provide the filter components with some additional data using props.

To avoid unnecessary coupling, FilterGroup should not know which filters will be rendered. Each filter adheres to a common specification/interface (implemented using mixins). Each filter has its own UI template.

How can this be implemented?

I tried using slots, but I can't figure out how to custom render the child components. If no slot is being used, this.$children is empty so I don't know which filters to render.

I could provide the filters like this:

<template>
  <FilterGroup :items="items" :filters="['ABCFilter', 'XYZFilter']/>
</template>

Then FilterGroup could dynamically import and render the filter components. It would even be possible to pass additional data. However, I think the resulting API is less readable and developer-friendly.

Is there a better way?

like image 618
Willem-Aart Avatar asked Oct 18 '22 00:10

Willem-Aart


1 Answers

I think you would like to use Dynamic Components for that. This allows you dynamically render a (child) component based on the data. In your example the filters.

The :is="ComponentName" defines the component that should be rendered. Use a props to pass down the data:

<template>
    <div class="app-body row">
        <template v-for="(child, index) in children">
            <component :is="child.viewName" :key="child.name" :data="child.data"></component>
        </template>
    </div>
</template>
like image 193
CodeTherapist Avatar answered Oct 23 '22 21:10

CodeTherapist