How to set attribute on a component inside a slot

2019-08-23 04:36发布

Problem

I have a BaseFormControl component which accepts id prop. It sets id prop value as both for attribute value on <label> element and id attribute value on a given input. As I want BaseFormControl to be a generic component re-usable with various input types, I pass the input as a slot. The code for the component below:

<script>
export default {
   props: {
     id: {
       type: String,
       required: true
     }
   }
};
</script>

<template>
  <div>
    <label :for="id">
      <slot name="label" />
    </label>
    <slot
      name="input"
      :id="id"
    />
  </div>
</template>

The problem with this approach is that <slot> doesn't pass any attributes to the slot contents, so :id isn't passed to the actual input at all.

So I tried setting it programatically:

export default {
   props: {
     id: {
       type: String,
       required: true
     }
   }

   created() {
     let inputSlot = this.$slots.input;
     if (inputSlot) {
       inputSlot[0].data.attrs.id = this.id;
     }
   }
};

It works perfectly in some cases (input passed as a slot has id attribute set properly in it's HTML), but in others it doesn't. What's especially interesting is that all the input components (what I put in the input slot is another base component, not a generic <input> tag) actually have it's this.$attrs properly populated with id, but sometimes it appears in actual HTML and sometimes it does not.

Can someone explain me that behavior, tell me what I'm doing wrong and how to solve that case?

Pen

I created a pen to illustrate the concepts. The only problem is in the pen everything works fine. In my app out of 2 selects on the page, only 1 has id set properly - the other one is rendered without id at all (though id is set in it's this.$attrs).

1条回答
欢心
2楼-- · 2019-08-23 04:55

The problem with this approach is that doesn't pass any attributes to the slot contents,

What yoou are doing is passing id to the slot as slot data. Which means you are creating a scoped slot.

You can access this data in the BaseFormControl using the slot-scope attribute.

<BaseFormControl :id="'myInput'">
  <p slot="label">Input label</p>
  <input slot="input" slot-scope="props" :id="props.id" type="text" placeholder="type anythin">
</BaseFormControl>

PS:

if you are passing id as a prop you can directly use it to set the id of the input as below

<BaseFormControl :id="'myInput'">
  <p slot="label">Input label</p>
  <input id="myInput" type="text" placeholder="type anythin">
</BaseFormControl>
查看更多
登录 后发表回答