![require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages](https://cdn.sanity.io/images/cgdhsj6q/production/be8ab80c8efa5907bc341c6fefe9aa20d239d890-1600x1097.png?w=400&fit=max&auto=format)
Security News
require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
@oarepo/data-editor
Advanced tools
A library for editing of rendered JSON data.
@oarepo/data-editor
requires @oarepo/data-renderer
to be installed as well.
yarn add @oarepo/data-editor
yarn add @oarepo/data-renderer
To register/configure the library, add a new boot file to quasar (or main.js for vue-cli projects):
import DataEditor from '@oarepo/data-editor'
import DataRenderer from '@oarepo/data-renderer'
export default async ({ Vue, store, router }) => {
Vue.use(DataEditor, {})
Vue.use(DataRenderer, {})
}
To use data editor, add data-editor
to template. data-editor
acceptsrecord
, options
, layout
and pathLayouts
and renders interface to edit received data with buttons for editing, addition and removal based on data type.
Dialog components and default values can be passed to data-editor
.
record
contains json data to be passed to data-editor.
record: { object: { a: 1 } }
record: { array: [1, 2] }
record: { array: [{ a: 1 }}, { b: 2 }] }
record: {}
options
may consist of schema, extraProps.
schema
of rendered data (inline, block, table, flex), defaults to table
options: { schema: table }
options: { schema: inline }
extraProps
(submit, cancel method for data editor)
options: { extraProps: { submit: { submit: this.submit, cancel: this.cancel } } }
layout
can be used to define the layout of an empty record, to associate dialog components or default values with props, to define children.
layout: [{ 'path': 'a', 'label': 'a' }]
layout: [{ 'path': 'a', 'label': 'a', dialogComponent: DialogComponent, dynamic: true }]
layout: [{ 'path': 'a', 'label': 'a', defaultValue: () => 1, dynamic: true }]
layout: [{ 'path': 'a', 'label': 'a', defaultValue: defaultValue, dynamic: true }]
pathLayouts
can be used to associate dialog components or default values with objects or arrays regardless of their position within the layout.
* simple default value options: { pathLayouts: { simpleArray: defaultValue: () => 1 } }
* complex default value options: { pathLayouts: { complexArray: defaultValue: () => { a: 1 } } }
If there is a complex value in layout
and not in data
, then this complex value must be created by clicking displayed button before it and its content can be edited.
layout
and pathLayouts
are described in more detail here: https://github.com/oarepo/data-renderer/
Specifies dialog component to be used with data editor, e.g. dialog to add a new object with default property to array, dialog to enter property and value to be added to object etc.
Examples are located at /src/components:
Example of a simple object. Src at /src/components/SimpleEdit.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
import Vue from 'vue'
export default {
name: 'simple-edit',
data: function () {
return {
record: {
Contact: {
Phone: '+420123123123',
Email: 'mary.black@gmail.com'
}
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
},
layout: {
showEmpty: true
}
}
},
methods: {
submit ({ context, prop, value, op }) {
isNaN(value)
if (op === 'add') {
Vue.set(context, prop, value)
}
if (op === 'replace') {
if (context[prop] === undefined) {
Vue.set(context, prop, value)
} else {
context[prop] = value
}
}
},
cancel (props) {
console.log('cancelling')
}
}
}
</script>
Example of a simple array. Src at /src/components/SimpleArray.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
import Vue from 'vue'
export default {
name: 'array-edit',
data: function () {
return {
record: {
keywords: ['first keyword', 'second keyword']
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
},
layout: {
children: [
{
prop: 'keywords',
label: {
label: 'keywordArray'
},
item: {
label: {
label: 'keyword'
}
}
}
]
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
context[prop] = value
}
}
if (op === 'replace') {
Vue.set(context, prop, value)
}
if (op === 'remove') {
if (Array.isArray(context)) {
context.splice(prop, 1)
} else {
delete context[prop]
}
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
Example of a complex array with default value for newly added items. Src at /src/components/SimpleArray.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
export default {
name: 'default-value-complex-array-edit',
data: function () {
return {
record: {
contact: [{ email: 1 }, { phone: '+420123123123' }]
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
},
layout: {
children: [{
prop: 'contact',
additionalProps: { defaultValue: () => ({ phone: '+420123123124' }) }
}]
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
context[prop] = value
}
}
if (op === 'replace') {
context[prop] = value
}
if (op === 'remove') {
if (Array.isArray(context)) {
context.splice(prop, 1)
} else {
delete context[prop]
}
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
Example of a complex array with dialog for addition of new items. Src at /src/components/ComplexArrayDialogEdit.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
import Vue from 'vue'
import DialogComponent from './DialogComponent'
export default {
name: 'complex-array-dialog-edit',
data: function () {
return {
record: {
contact: [{ phone: '+420123123124' }, { email: 'mary.black@gmail.com' }]
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel,
dialogComponent: DialogComponent
}
},
layout: {
children: [
{
prop: 'contact'
}
]
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
Vue.set(context, prop, value)
}
}
if (op === 'replace') {
context[prop] = value
}
if (op === 'remove') {
if (Array.isArray(context)) {
context.splice(prop, 1)
} else {
delete context[prop]
}
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
Example of an empty record with layout and dialog. Src at /src/components/NonExistingObjectDialogEdit.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
import Vue from 'vue'
import DialogWithPropertyComponent from './DialogWithPropertyComponent'
export default {
name: 'non-existing-object-dialog-edit',
data: function () {
return {
record: {},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
},
layout: {
showEmpty: true,
children: [
{
prop: 'object',
additionalProps: { dialogComponent: DialogWithPropertyComponent },
children: []
}
]
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
Vue.set(context, prop, value)
}
}
if (op === 'replace') {
context[prop] = value
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
Example of a dialog component. Src at /src/components/DialogComponent.vue:
<template lang="pug">
q-dialog(ref="dialog" @hide="onDialogHide")
q-card
q-card-section
q-form(ref="form")
q-input(label="value" v-model="value")
q-card-actions(align="right")
q-btn(color="primary" type="submit" label="OK" @click="onOKClick")
q-btn(color="primary" label="Cancel" @click="onCancelClick")
</template>
<script>
export default {
name: 'dialog-component',
data: function () {
return {
value: null
}
},
props: {
initialValue: Object
},
mounted () {
if (this.initialValue) {
this.value = this.initialValue
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async onOKClick () {
if (await this.$refs.form.validate()) {
this.$emit('ok', { phone: this.value })
this.hide()
}
},
onCancelClick () {
this.hide()
}
}
}
</script>
Example of object with default value as a function and dialog component. Src at /src/components/AdditionalPropsEdit.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout")
</template>
<script>
import DialogWithPropertyComponent from './DialogWithPropertyComponent'
import Vue from 'vue'
function defaultValue ({ context, layout }) {
for (const prop of 'abcdefghijklmnopqrstuvwxyz'.split('')) {
if (context[layout.prop][prop] === undefined) {
return { prop: prop, value: 'keyword' }
}
}
}
export default {
name: 'additional-props-edit',
data: function () {
return {
record: {
creator: { name: 'Mary Black' },
contact: { phone: '+420123123124' },
keywords: {}
},
layout: {
children: [
{ prop: 'creator', additionalProps: { dialogComponent: DialogWithPropertyComponent } },
{ prop: 'contact', additionalProps: { dialogComponent: DialogWithPropertyComponent } },
{ prop: 'keywords', additionalProps: { defaultValue: defaultValue } }]
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
Vue.set(context, prop, value)
}
}
if (op === 'replace') {
context[prop] = value
}
if (op === 'remove') {
if (Array.isArray(context)) {
context.splice(prop, 1)
} else {
delete context[prop]
}
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
Example of a record as tree with a complex default value for addition of new items. Src at /src/components/TreeEdit.vue:
<template lang="pug">
data-editor(:record="record" :options="options" :layout="layout" :path-layouts="pathLayouts")
</template>
<script>
import Vue from 'vue'
export default {
name: 'tree-edit',
data: function () {
return {
record: {
object: [
{ creator: 'Mary Black' },
{
contact: [
{ phone: '+420123123123' },
{ email: ['mary.black@gmail.com'] }]
}]
},
options: {
schema: 'table',
extraProps: {
submit: this.submit,
cancel: this.cancel
}
},
layout: {
children: [
{
prop: 'object',
additionalProps: { defaultValue: () => ({ keywords: ['first keyword', 'second keyword'] }) }
}
]
}
}
},
methods: {
submit ({ path, context, prop, value, op, pathValues }) {
if (op === 'add') {
if (Array.isArray(context)) {
context.push(value)
} else {
Vue.set(context, prop, value)
}
}
if (op === 'replace') {
context[prop] = value
}
if (op === 'remove') {
if (Array.isArray(context)) {
context.splice(prop, 1)
} else {
delete context[prop]
}
}
},
cancel ({ props }) {
console.log('cancelling')
}
}
}
</script>
FAQs
A library for editing of rendered JSON data.
We found that @oarepo/data-editor demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
Security News
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.