Wrapping JSONEditor in Vue as Well as Laravel Blade

Posted: 2017-11-01 12:11:50

UPDATED November 05 2017

This will cover how to make a JSONEditor component that I can then use in a Blade template and listen to events.

You will end up with this:

First making sure I have all the packages I need:

  //package.json
  "devDependencies": {
    "axios": "^0.17",
    "bootstrap-sass": "^3.3.7",
    "cross-env": "^5.0.1",
    "jquery": "^3.2",
    "laravel-mix": "^1.0",
    "lodash": "^4.17.4",
    "vue": "^2.1.10"
  },
  "dependencies": {
    "select2": "^4.0.5",
    "jsoneditor": "^5.9.6"
  }

And to load it into my bootstrap file:

//resources/assets/js/bootstrap.js
try {
    window.$ = window.jQuery = require('jquery');
    require('bootstrap-sass');
    require("select2");
    require("jsoneditor");
} catch (e) {
    console.log("Error loading jquery");
}

Which gets pulled in by my app.js which I also register the global component:

//resources/assets/js/app.js
require('./bootstrap');

window.Vue = require('vue');

/**
  * Using this as a globle event emmitter for components to easily talk to other components
  */
window.EventBus = new Vue();


Vue.component('cat-json-editor', require('./components/JSONEditor'));

Vue.component('cat-config-field', require('./components/ConfigField'));
//end of file

The app.js and bootstrap.js are default workflows of Laravel

Then I will make the component:

//resources/assets/js/components/JSONEditor.vue
<template>
    <div>
        <div id="jsoneditor"></div>
    </div>
</template>

<script>

    import JSONEditor from 'jsoneditor';

    export default Vue.extend({
        props: ['config'],

        mounted: function () {
            let self = this;
            let container = document.getElementById('jsoneditor');
            let options = {
                onChange: function() {
                    EventBus.$emit('config-updated', editor.get());
                },
                modes: ["tree", "text"],
            };
            let editor = (container) ? new JSONEditor(container, options) : null;
            if(container) { editor.set(window.config); }
        }
    });
</script>


<style type="text/css">
    #jsoneditor {
        width: 800px;
        height: 600px;
    }
</style>

Here I register the props and I setup some config using code I placed into window from my controller. You can use this tool for this process. I could have passed it into the component but chose not to.

So now when there is a change it will emit the change to the global EventBus

Now for the ConfigField component:

<<template>
    <div>
        <input type="hidden" id="config" name="config" class="form-control" rows="30" v-model="config">
    </div>
</template>


<script>

    export default Vue.extend({

        data() {
            return {
                'config': JSON.stringify(window.config)
            }
        },

        methods: {
            configUpdated: function(json) {
                this.config = JSON.stringify(json);
            }
        },

        created() {
            EventBus.$on("config-updated", this.configUpdated);
        }

    });

</script>

With these two components in place I now need to add the components to the HTML template.

After this is setup my Blade file has the needed Vue listener etc to update the form (non-ajax) as needed:

@push('scripts')
    <script>
        new Vue({
            el: '#config_form',

        })
    </script>
@endpush
<!-- Form above this that is doing all the form submission work -->
<div id="config_form">
    <label for="config">Config</label>
    <cat-json-editor></cat-json-editor>
    <cat-config-field></at-config-field>
</div>

In this case I am taking advantage of Blades stack feature

And the minor amount of work here just mounts Vue onto the #config_form

Then I use Vue to listen to the event "config-updated". From there, since this is not about Ajax requests, I update the hidden field on the form. I could have done this with JQuery but just wanted to get use to this Vue workflow. Also I could see sending this over Ajax sooner than later even if just for validation notices etc.

Here is a quick look at the Scope of the objects: