2

Hi everybody, please pardon my english :-)

I have a Vue component that can take dynamic slots (the names of the slots will depend on a props).

I use it on several places and some of the slots are always present.

To avoid redundancy, I'm looking for a way to create a component that "wrap" the final component to allow me to define only the additionals slots.

If there is an "obvious" way to achieve it, I may have missed it :-)

Code example

Without a "wrap component"

<b-table
  show-empty
  small
  hover
  
  [...some others and always present props...]

  :items="aDataVarThatWillChangeBasedOnTheContext"

  [...some others and uniq props...]
>
  <template slot="same-1">
   A slot that will always be present with the same content (for example, a checkbox in the first column)
  </template>

  <template slot="same-2">
   A slot that will always be present with the same content (for example, some action buttons in the last column)
  </template>

  [...some others and always present slots...]
  
  <template slot="not-the-same">
   A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
  </template>

  [...some others and uniq slots...]
</b-table>

With a "wrap component"

<my-b-table
  :items="aDataVarThatWillChangeBasedOnTheContext"
>
  <template slot="not-the-same">
   A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
  </template>
</my-b-table>

Note: The dynamic slot name is not predictible. If I suddenly need a "foo" column, I should be able to pass a "foo" slot (and a "HEAD_foo" slot, in my case)

Some researches

I read here that:

They’re (the functionnal components) also very useful as wrapper components. For example, when you need to:

  • Programmatically choose one of several other components to delegate to
  • Manipulate children, props, or data before passing them on to a child component

And "Manipulate children, props, or data before passing them on to a child component" seems to be exactly what I need.

I looked on render function but a lot of things seems to be not implemented, like the v-model, and I have difficulties to figure out how to pass dynamic slots...

Thank you in advance for your(s) answer(s) !

up: At the 07.03.2018 I still dont have any idea about how to solve this case

2 Answers 2

2

Found the answer that was somehow unclear to me that month ago.

("Dynamic" means here "not explicitely declared by the component, but gived by the parent")

Wrapper component

Props and scoped slots can be gived dynamically by the options object of createElement function.

"Simple" Slots can be gived dynamically by the childs array of createElement function.

Wrapped component

Props can't be dynamic unless the component is functional.

Slots can always be retrieved dynamically.

Scoped slots can be retrieved only if the component isn't functional.

Conclusion

It's not possible to have dynamics props and scoped slots at the same time...

But it's possible to declare all the needed props and then to use a "non-functionnal" component as wrapper and as wrapped.


How to

Retrieve from non-functional component

var component = Vue.component('component-name', {
  props: ['name', 'of', 'the', 'props'],
  
  // [...]
  
  aMethod: function () {
    this._props // all the declared props
    this.$slots // all the slots
    this.$scopedSlots // all the scoped slots
  }
});

Retrieve from functional component

var component = Vue.component('component-name', {
  functional: true,

  render: function (createElement, context) {
    context.props // all the props
    context.children // all the slots as an array
    context.slots() // all the slots as an object
  }
});

Give to child component

var component = Vue.component('component-name', {
  render: function (createElement) {
    return createElement(
      childComponent,
      {
        props: propsToGive,
        scopedSlots: scopedSlotsToGive
      },
      [
        // non-scoped slots to give
        createElement('slot-tag-name', {slot: 'slot-name'})
      ]
    );
  }
});

References

https://v2.vuejs.org/v2/guide/render-function.html

https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments

https://v2.vuejs.org/v2/guide/render-function.html#Functional-Components


Sandbox

https://jsfiddle.net/5umk7p52/

0

Just make a regular component out of your customized <b-table>.

You'll need to define an items prop for your component to pass as the items for the <b-table> component.

And, to define a slot for your component, you'll need to use the <slot> tag, specifying the name using the name attribute.

If you'd like to make one of the slots from the <b-table> component accessible in the <my-b-table> component, simply pass a <slot> tag as the content of the slot in your custom component.

It would look something like this:

Vue.component('my-b-table', {
  template: `
    <b-table
      show-empty
      small
      hover
      :items="items"  
    >
      <template slot="same-1">
        Content to pass to the b-table's slot
      </template>

      <slot name="not-the-same">
        A slot that is only used in this context
      </slot>

      <template slot="last_edit">
        <slot name="last_edit">
          A slot to pass content to the b-table component's slot
        </slot>
      </template>
    </b-table>
  `,
  props: { items: Array },
});
6
  • It's sadly not so simple: With the b-table component you can use a slot for displaying a particular column in a particular way. For example: If you have a column named "last_edit", you can use a slot like this: ``` <template slot="last_edit"> <!-- custom HTML / JS / ... display for the "last_edit" cells --> </template> ``` As it's a "dynamic" slot, I would like to "give" them to the b-table child component
    – Ettapp
    Commented Feb 15, 2018 at 15:37
  • I'm not sure I follow. You mean you want that slot to be in your <my-b-table> component as well?
    – thanksd
    Commented Feb 15, 2018 at 16:07
  • Yeah, I need to be able to give a slot to the b-table through my-b-table
    – Ettapp
    Commented Feb 18, 2018 at 11:10
  • The difficulty is that I dont know in advence the slot name to pass through the my-b-table component as they will be different in every usages: <template slot="<I-dont-know-for-now>"> <slot name="<I-dont-know-for-now>"> A slot to pass content to the b-table component's slot </slot> </template> Maybe the books page will display a date, and the articles page will display a price, both "page component" should be able to use my-b-table to avoid redundancy to display checkboxes, ids, and others identicals fields and both should be able to describe how to handle specific fields
    – Ettapp
    Commented Feb 20, 2018 at 11:45
  • Can you please add all of your requirements as an edit to your question and I'll try to see if I can come up with a different answer?
    – thanksd
    Commented Feb 20, 2018 at 14:10

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.