Closed miljan-aleksic closed 7 years ago
This should be solvable with scoped Slots
And if that syntax doesn't suit you, you can pass component options as props as well, and simply use them in a dynamic component:
// parent
<child :component="{template: ....}" />
//child
<template>
<component :is="component"/>
</template>
<script>
props: ['component']
</script>
ScopedSlots are a great addition and they could be used to customize the output of each child, but they don't solve this situation. They are simple functions to be used during the childs rendering, but the idea here is to leave that to the parent. To make this more clear, let's take the example 1:
<vk-table>
<vk-table-column>
<template slot="header" scope="props">
My Customi Header Inner Content
</template>
<template slot="cell" scope="props">
My Custom Cell Inner content
</template>
</vk-table-column>
</vk-table>
Cool, now we know what the inner content for each column should be look like. With that information in the parent, ideally, we would do:
<table>
<thead>
<tr>
<th v-for="col in $childrens">
{ col.$scopedSlots.header(col) || col.header }
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows">
<td v-for="col in $childrens">
{ col.$scopedSlots.cell({ row, col }) }
</td>
</tr>
</tbody
</table>
Note: for clarity and brevity I am mixing JSX with template declaration.
The above example could not work because $childrens
is not available unless <slot></slot>
is used somewhere, which in this case doesn't have place, there is no need for a default child rendering.
I'm afraid I have trouble understanding what you are trying to achieve - looks like you are simply trying to pass down data, but want to use templates to do that. Why not just pass down an array as a prop?
Ok, let me put all the cards on the table. This is an adapted extract of a real component workflow:
<template>
<table
{ this.$slots.default }
<thead>
<tr>
{ this._l(this.$children, col => col.headerRender.call(col._renderProxy, h)) }
</tr>
</thead>
<tbody>
{ this._l(this.data, (row, rowIndex) =>
<tr>
{ this._l(this.$children, col =>
col._cellRender.call(col.renderProxy, h, { row, rowIndex })
) }
</tr>
)}
</tbody>
</table>
</template>
render (h) {
return (<col></col>)
},
headerRender (h) {
const scopedSlot = this.$scopedSlots && this.$scopedSlots.header
return (<th>{ scopedSlot ? scopedSlot() : this.header }</th>)
},
cellRender (h, { row, rowIndex }) {
const cell = this.cell
const scopedSlot = this.$scopedSlots && this.$scopedSlots.cell
return (<td>{ scopedSlot ? scopedSlot({ row, rowIndex }) : row[cell] }</td>)
}
extends: VkTableColumn,
headerRender (h) {
// using a similar approach as default renders instead a Selectable Checkbox
},
cellRender (h) {
// using a similar approach as default renders instead a Selectable Checkbox
}
<VkTable>
<VkTableColumnSelect />
<VkTableColumn header="Simple Header" cell="dataKey" />
<VkTableColumn>
<template slot="header" scope="props">Custom Header inner content</template>
<VkTableColumn>
<VkTable>
Please take a step back and describe what use case you are trying to achieve. The code samples are quite confusing without explanation on what the design constraints are.
I have created a jsfiddle describing the use case behind VkTable.
Since that is, once again, just code, and no explanation of you goal (I assume you are just too far "in the zone" to understand that we can't follow you easily with a few lines of code), I'll try to summarize what I understood as your design goal and you can tell me if my guess is right:
<vk-table>
scopedSlots
functions) to it to it can render the content according to those instructions.Much like, e.g. Recharts (for React) does it, in part, for Charts:
<LineChart width={500} height={300} data={data}>
<XAxis dataKey="name"/>
<YAxis/>
<CartesianGrid stroke="#eee" strokeDasharray="5 5"/>
<Line type="monotone" dataKey="uv" stroke="#8884d8" />
<Line type="monotone" dataKey="pv" stroke="#82ca9d" />
<Tooltip /> <!-- this is not rendered in place, it rather defines a behaviourn -->
</LineChart>
Getting close?
Sorry to be so deep "in the zone" LOL. Yes, @LinusBorg, you summarized it pretty well, thanks :)
Linus i think u are on spot with what miljan is saying (as an interface to parent component). Ive actually thought about the exact same components before (a datagrid and data column definitions), and tabs.
I've managed to implement the tabs with the use of render functions, but it was not very straightforward to implement... i had to filter out the 'tab' component's vnodes and get its 'label' propdata in order to render the tab header.
Not straightfoward but definitely doable in vuejs2 with the use of render functions
@pohnean is right, all this is doable with workarounds and Vue2, but being a quite common issue (judging the forum) it would be nice to have an official solution.
We could think of those like functional/declarative components. They should accept props and composedSlots, but with no render of any kind.
My gut feeling is that this is not a good idea as an additional API. Those components essentially are an empty shell which we only need to get their propsData into the main component.
This is has nothing in common with what it means when we talk about a "component" in Vue in any other situation.
So I have a bad feeling about introducting an API that essentially says:
"if you set this setting, then
<someComponent/>
will not behave like a component at all, it's basically a fancy way to pass props".
Addtionally, the vnode API is part of the public API, so using it is not automatically a "hack".
If you want to use templates, the good news is, you can! You can access this.$slots
in beforeMount()
and beforeUpdate()
, using their vnode's content to prepare all the data nessessary for the following render function (which can be created by vue-loader from a template)
Thank you @LinusBorg and don't worry, I was expecting this kind of answer. A similar one I got when exposed a template dilema, back then in v1, which was now finally solved in v2.1 with ScopedSlots. Probably at the time I was also too far into the zone and didn't managed to provide a good presentation or any valid solution. So, I hope this will arise again naturally, evolve, and eventually get solved.
Meantime, I will keep with my workarounds. You can close this ticket and if you have the time, perhaps you are up to a challenge related to this topic. Basically, without the workarounds, I can't find a way to apply a simple Tab transition. Details in the forum.
I will close this now. Further discussion is fine, but I think it's clear that such a feature will not happen anytime soon.
I found this issue by searching what is the this._l
thing (still don't have an answer though).
I think that I want to implement exactly the same thing.
I like the way how Table component from element library can be used - a very straightforward. So I wanted to implement something similar but my own and with less features, well you know... :) Just some simple table component with neat api.
But I was really confused by reading element source code, there are plenty of jsx and some this._l
, this._renderProxy
. And it seems like there is just no way to achieve similar component interface without all those hacks.
This issue is more than a year old.
Today, I would use the provide/inject for such functionality.
This issue is closed. Please use forum.vuejs.org for further questions.
I found this issue by searching what is the
this._l
thing (still don't have an answer though).I think that I want to implement exactly the same thing.
I like the way how Table component from element library can be used - a very straightforward. So I wanted to implement something similar but my own and with less features, well you know... :) Just some simple table component with neat api.
But I was really confused by reading element source code, there are plenty of jsx and some
this._l
,this._renderProxy
. And it seems like there is just no way to achieve similar component interface without all those hacks.
@Alendorff as far as I understood Vue.prototype._l
is a short hand for renderList
the helper used by v-for
so vue template code
<td v-for="(column, index) in columns" calss="table_cell" />
in jsx would be
{ _l(columns, (column, index) => <td calss="table_cell" /> ) }
Hi!
in several components I find myself doing few workaround to accomplish the child components be a simple data representation.
Example 1 - Table
The
vk-table-column
purpose is to collect the data but leverage the rendering tovk-table
which will iterate over the children as necessary to accomplish the Header, Rows, Cell combination.Example 2 - Tabs
Similar as in previous example but additionally the Tabs content should be rendered using single Transition.
To the point
In both examples, the children can't be used out the default way to accomplish the special rendering. There are several workarounds but are tricky, unsupported and of course not best practice, so I would like to start a discussion about solving this particular need.
A solution could be having a way to initiate those $children with no render or template set as out of document components. They would be accessible early in the parent for immediate use during rendering.