agm1984
agm1984

Reputation: 17160

How to filter children components in Vue based on their component type?

I am having trouble identifying children components in Vue.

I have this markup here:

<parent>
    <child-one>
    </child-one>

    <child-two>
    </child-two>

    <child-one>
    </child-one>
</parent>

The parent component is functional, so it is doing this:

render(createElement) {
    return createElement('div', this.$slots.default);
},

I want to iterate over this.$children and return an Array of VNodes kind of like this:

const matchingChildren = this.$children
    .filter(child => child.isChildOneType === true)

return createElement('div', {}, matchingChildren)

How do I do that?

What and where do I need to filter?

I'm pretty sure I can do it by setting a type prop on child-one, and then using this.$children.filter(child => child.$attrs.type === 'special'), but I want to filter them based on the fact they are child-one components.

I'm trying to make the example simple, but this is for tabbed pages, so I am not interested in conditional rendering. I'm trying to transform the markup into different DOM output, and I need to filter children of a specific type.

I have researched $attrs and $options as hooks that I could use, but if I use attrs, I need to add a prop to each component. I would like to avoid that since they are all of type child-one. I also can't seem to add a static property to child-one. The $options field is always empty.

Upvotes: 3

Views: 2280

Answers (1)

Potato Salad
Potato Salad

Reputation: 4650

There is nothing wrong or non-standard by setting a specific property to use as a filtering criteria such as

this.$children.filter(child => child.$attrs.type === 'special')

If your child components are siblings of other non-component markup, or those of you dont want filtered, then you have no choice but to set a prop indicating that they are the components that you need.

In the browser, the child nodes are plainly generic and cannot be properly isolated from one another without using some sort of identifier; such as a tag name, an id, attribute, or property. Nodes rendered via Vue, React, HTML, native JS whatsoever are all in all the same in the browser's perspective.

Since you can't use the component names like child-one because they will be rendered like normal HTML, you can just plainly add an attribute/v-attribute to each component wrapper on your Vue templates and simply filter them out like normal nodes once rendered.

<parent>
    <child-one>
         <div class="wrapper" componentType="1"></div>
    </child-one>

    <child-two>
         <div class="wrapper" :componentType="data.type"></div>
    </child-two>

    <child-one>
         <div class="wrapper" componentType="1"></div>
    </child-one>
</parent>

Or you can add attributes on the component themselves, which I have never tried before so I can't help you with that

Upvotes: 3

Related Questions