-
Notifications
You must be signed in to change notification settings - Fork 66
lesson 17
In the last lesson, we have successfully create properties in our MyVuetable component allowing passing data in from the main component/instant. But the only remaining thing we are not able to do is the scoped slots.
Scoped slots has been newly introduced in Vue 2.1 and it is a very powerful concept when working with Vue.js. It offers a more convenient way of flexible content distribution. Before the introduction of scope slots, you would have to create another component for the job.
As of the current release of Vue 2.3, there is still no way to pass the scoped slot down into the component via template. The only way possible is to implement the render function where you'll have access to scopedSlots data object. This will allow you to pass down the scoped slot into your component. But this means you will have to give up the template and render your component using the render function only.
This seems like a daunting task. Luckily, in our case, this is not that hard but you will need some background knowledge before proceeding. Read the following topic in Vue documentation first, then come back to continue with the tutorial. You don't need to understand everything though.
It is possible to start making your component with render function from the beginning if your component is not so complex (e.g. does not have a complex html structure). But template is actually more natural and a lot easier to comprehend, especially if you're still new to making Vue component.
In fact, you don't really have to care or learn about render function until you really need to use it. Since we would like our users to be able to use scoped slots from our MyVuetable component and pass this down to Vuetable, we need to
be able to access to scopedSlots data object which only available inside the render function.
So, let's begin by reviewing the current template of our MyVuetable. This will help guide us on what we need to do.
<template>
<div class="ui container">
<filter-bar></filter-bar>
<vuetable ref="vuetable"
:api-url="apiUrl"
:fields="fields"
pagination-path=""
:per-page="10"
:multi-sort="true"
:sort-order="sortOrder"
:append-params="appendParams"
detail-row-component="detailRowComponent"
@vuetable:cell-clicked="onCellClicked"
@vuetable:pagination-data="onPaginationData"
>
//... this used to be where scoped slot "actions" was ...
</vuetable>
<div class="vuetable-pagination ui basic segment grid">
<vuetable-pagination-info ref="paginationInfo"
></vuetable-pagination-info>
<vuetable-pagination ref="pagination"
@vuetable-pagination:change-page="onChangePage"
></vuetable-pagination>
</div>
</div>
</template>Please note that the template above does not include the scoped slots "actions". As it should be passed down from the parent component, so it no longer needs to be there.
Fear Not! It's easier than you might think. There's a trick to that and I'll show you how.
The render function is nothing more than mimicking the browser in rendering the HTML. So, if you look at the stardard HTML page, you would see layers of layers of HTML tags inside with the outermost layer is the <html> tag.
<html>
<head>
<title></title>
</head>
<body>
<div class="container">
<div class="header">
//...
</div>
<div class="content">
//...
</div>
<div class="footer">
//...
</div>
</div>
</body>
</html>The render function that you're going to write is exactly the same. You render from the outermost layer into the innermost one, step by step, passing the createElement argument (usually denoted with h for brevity) down to the inner layer, so that it can be used to render other stuff inside its block.
Let's digest our template down a bit and I'll explain why it is digestible to this.
<template>
<div>
<filter-bar></filter-bar>
<vuetable></vuetable>
<div>
<vuetable-pagination-info></vuetable-pagination-info>
<vuetable-pagination></vuetable-pagination>
</div>
</div>
</template>After all, our component structure wasn't so complex. What makes it complex is the functionality inside that has been exposed through its properties and events. When we strip them down, what's left is the skeleton that we can comprehend.
That, however, doesn't mean that we do not need those attributes and directives we omit. We do, but we will deal with them one by one inside its own block.
Let's discuss each block and starting writing our render function.
Every Vue component must has exactly one root element, which in our case is the outermost <div> block. To be precise, the actual block looks like this. (We will leave out the <template> tag from now on.)
<div class="ui container">
<filter-bar></filter-bar>
<vuetable></vuetable>
<div></div> <!-- pagination block -->
</div>- It has
uiandcontainerclasses - It contains three children, which are
<filter-bar>-
<vuetable>, and - pagination
<div>
With this information, we can start writing our render function for the outermost layer, like so.
render (h) {
return h(
'div', //.. first parameter,
{}, //.. second parameter,
[] //.. third parameter
)
},Note
Therenderfunction is not inside themethodssection, it lives at the same level as theprops,data, andmethodssection!
When you declare the render function, Vue will pass in the createElement argument as a parameter. Since we are going to use this argument very often, we should name it very short. And by convention, it usually names h.
The createElement argument (from now on will be referred to as h) is actually a function, so to use it you have to call it and supplies parameters to it and must return itself back to its parent so that the execution can be chained and handled properly by the main instance.
- The first parameter is the "tag" that you want to render out as HTML tag, in this case, a
div. - The second parameter (optional) is the Data Object describing the characteristics of the element to be rendered.
- The third parameter (optional) can be either a string that will be inside the element tag (e.g.
<title>Hello</title>) or array of its children.
In this tutorial, we will always write its parameters in its own line, so that it is easier to notice.
Here is the complete render function of our outermost div block.
render (h) {
return h(
'div',
{
class: { ui: true, container: true }
},
[
h('filter-bar'),
this.renderVuetable(h),
this.renderPagination(h)
]
)
},We specify that this div should have ui and container class inside the Data Object in the second parameter.
In the third parameter, we specify that this div block will contain 3 children:
- the first one (
filter-bar) does not have any attribute, so we just usehto render it out. - the second one (
vuetable) will contain quite a lot information, so we just delegate it to another method (renderVuetable) to do the rendering of its block. - the third one will also contain some attributes, so we will also delegate to another method (
renderPagination) to render its own block as well.
- Your first Vuetable
- Displaying more fields
- Cleaning up code
- Make change to field title
- Column alignment
- Format fields using
callbackoption - Adding pagination
- Displaying pagination information
- Customizing Vuetable
- Make columns sortable
- Using special fields
- Adding Detail Row
- Adding Search Filter
- Moving Field Definitions to another file
- Passing Props to MyVuetable - Part 1
- Passing Props to MyVuetable - Part 2
- Passing Scoped Slot to MyVuetable
- Using Twitter's Bootstrap CSS with Vuetable
- Pagination for Twitter's Bootstrap