@oarepo/data-renderer v2.4.9
@oarepo/data-renderer
A library for providing simple (but configurable) UI for rendering JSON data.
Example
<template lang="pug">
data-renderer(:data="data")
</template>
<script>
export default {
data: function() {
return {
data: { 'title': 'Hello world' }
}
}
}
</script>Installation
yarn add @oarepo/data-renderer vue-uidTo register/configure the library, add a new boot file to quasar (or main.js for vue-cli projects):
import DataRenderer from '@oarepo/data-renderer'
import VueUid from 'vue-uid';
export default async ({ Vue, store, router }) => {
Vue.use(VueUid);
Vue.use(DataRenderer, {})
}What the component does
DataRendererComponent component iterates the layout tree and converts layout
into a VueJS component. Without any settings, the created component tree will look like:
wrapper.wrapperClass(:style="wrapperStyle" ...wrapperAttrs)
label.labelClass(:style="labelStyle" ...labelAttrs)
| labelValue
value.valueClass(:style="valueStyle" ...valueAttrs) {{ valueOnPath }}
childrenWrapper.childrenWrapperClass(:style="childrenWrapperStyle" ...childrenWrapperAttrs)
// children rendered in hereThis tree is defined via the following layout:
elementProperties = {
element: null,
class: {}, // element classes
style: '', // element style
attrs: {}, // element attrs
visible: true // set to false to not render the element, just its content
}
layout = {
wrapper: {
...elementProperties,
element: 'div',
},
label: {
...elementProperties,
element: 'label',
label: 'Label to be shown',
},
value: {
...elementProperties,
element: 'div',
},
'children-wrapper': {
...elementProperties,
element: 'div',
},
'array-wrapper': {
...elementProperties,
element: 'div',
},
prop: '', // json path pointing to the displayed value inside record metadata
showEmpty: false, // if true, the element will be rendered even if there is no value
children: [] // layout of children of this node
}Every property can be a function func({context, layout, data, vue, paths, ...}) where context
points to the actual parts of the data that is being rendered. To use property as a function, wrap it inside f:
export default {
layout: {
prop: 'thumbnail',
value: {
component: 'img',
attrs: {
src: f(({ value }) => { return value }),
width: '16'
}
}
}
}Usage
To apply this layout, add to template:
<template lang="pug">
data-renderer(:layout="layout" :data="data"
schema="block|inline|table|<object with default definition>")
</template>Data
data passed to data renderer must be an object. To render data consisting of an array of objects, data renderer can be wrapped with an element using v-for directive. Example:
<template lang="pug">
div(v-for="item in array")
data-renderer(:data="item")
</template>Layout
The layout element might contain the layout as shown above, or shortcut can be used:
export default {
layout: {
title: {
label: {
value: 'Title label'
}
},
location: {
children: [ ... ]
}
}
}Rendering children
Array and object children can be defined in layout. The array or object itself is placed inside children in layout
and may contain another array of children. See the examples below.
Object layout definition may look like this:
export default {
data: {
object: {}
},
layout: {
showEmpty: true,
'children-wrapper': {
element: 'div'
},
children: [
{
prop: 'location',
label: {
label: 'Location label'
},
children: [
{
prop: 'street',
label: {
label: 'Street'
}
},
{
prop: 'number',
label: {
label: 'Number'
}
},
{
prop: 'zipcode',
label: {
label: 'Zipcode'
}
}]
}]
}
}Layout of an array contains the item property with definition of layout for array items:
export default {
data: {
object: {}
},
layout: {
showEmpty: true,
'array-wrapper': {
element: 'div'
},
children: [
{
prop: 'Contact',
label: {
label: 'List of contacts'
},
item: {
label: {
label: 'Phone number'
}
}
}]
}
}If the item of an array is a complex value, then the item property in layout must contain children. Example:
export default {
data: {
object: {}
},
layout: {
showEmpty: true,
'array-wrapper': {
element: 'div'
},
children: [
{
prop: 'Contact',
label: {
label: 'List of contacts'
},
item: {
children: [
{
prop: 'phone',
label: {
label: 'Phone number'
}
}
]
}
}]
}
}Overriding parts of layout
It might be useful to be able to override the layout for selected paths.
To do this, pass :path-layouts property.
The value of the property is:
- object with keys (same as slot names but without the 'element' prefix) and value for the layout of the corresponding object at the given path
export default {
data: {
object: {
a: 'red text'
}
},
pathLayouts: {
a: {
value: {
class: ['text-red']
}
}
}
}Path details
As stated above, the path is composed based on the jsonpath of rendered data. The set of paths for each rendered node is constructed as follows:
export default {
layout: {
prop: "location",
children: [
{ prop: 'street' },
{ prop: 'number' },
{ prop: 'zipcode' }
]
}
}The path for the root is ['location']. The path for street is ['location-street', 'street'],
i.e. for each of the parent paths, '-street' is appended to the path and an extra street.
Translating labels
A function can be registered to create/translate labels. Set either a global labelTranslator when the module is
initialized or a :labelTranslator prop containing function with the following layout:
func({label, context, layout, data, vue, paths, schema})
and returning the translated label or null if the label should not appear. The default implementation adds ':'
after the label for inline schema.
Using the same logic, boolean values can be translated with :booleanTranslator.
Dynamic layout
If there is no layout specified for the object, it is created dynamically from the data passed to data-renderer.
Links
To render the value as a link, define <a></a> html tag and href attribute in pathLayouts.
export default {
a: {
value: {
element: 'a',
attrs: {
href: f(({url}) => { return url })
}
}
}
}Using slots before and after rendered value
Components for primitive values contain a before and after slot which can be used to render custom code before and after rendered value. Example:
<template lang="pug">
data-renderer(:layout="layout" :data="data")
template(v-slot:before)
div a
template(v-slot:after)
div b
</template>Rendering components before and after rendered data
To render custom component before or after rendered data, register component in layout, e.g.: before: CustomComponent, after: CustomComponent
Rendering custom components based on type of value
Custom components can be used based instead of default ones, when passed to :renderer-components property. Example:
<template lang="pug">
data-renderer(:layout="layout" :data="data" renderer-components="rendererComponents")
</template>export default {
data: {
a: 'string value',
b: 1,
c: 'string value',
d: true
},
rendererComponents:{
string: CustomComponent
}
}5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago