npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@oarepo/data-editor

v3.1.14

Published

A library for editing of rendered JSON data.

Downloads

18

Readme

@oarepo/data-editor

A library for editing of rendered JSON data.

Installation

@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, {})
 }

Usage

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

record contains json data to be passed to data-editor.

  • simple object: record: { object: { a: 1 } }
  • simple array: record: { array: [1, 2] }
  • complex array: record: { array: [{ a: 1 }}, { b: 2 }] }
  • empty record: record: {}

Options

options may consist of schema, extraProps.

  • schema of rendered data (inline, block, table, flex), defaults to table
    • table options: { schema: table }
    • inline options: { schema: inline }
  • extraProps (submit, cancel method for data editor)
    • options: { extraProps: { submit: { submit: this.submit, cancel: this.cancel } } }

Layout

layout can be used to define the layout of an empty record, to associate dialog components or default values with props, to define children.

  • basic layout: layout: [{ 'path': 'a', 'label': 'a' }]
  • layout with dialog component: layout: [{ 'path': 'a', 'label': 'a', dialogComponent: DialogComponent, dynamic: true }]
  • layout with default value: layout: [{ 'path': 'a', 'label': 'a', defaultValue: () => 1, dynamic: true }]
  • layout with default value as a function: 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/

Dialog component

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

Examples are located at /src/components:

simple object

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: '[email protected]'
        }
      },
      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>

Simple array

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>

Complex array with default value

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>

Complex array with dialog

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: '[email protected]' }]
      },
      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>

Record with dialog component and no data

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>

Empty object with dialog component and default value function

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>

Record as tree

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: ['[email protected]'] }]
          }]
      },
      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>