JavaScript API

New in version 2.11.

This document describes the JavaScript API available for django-jsonform widget.

Some use cases:

  • Dynamically modifying schema directly in the browser

  • Enabling/disabling inputs dynamically

  • Updating choices dynamically

  • Making AJAX requests on value changes

API

Note

django-jsonform uses react-json-form under the hood.

So, this is a shortened documentation of the actual API. We’ll only look at the functions which only concern the Django side of things.

reactJsonForm.getFormInstance(id)

Use this function to get an instance of the form widget.

The id is the ID of the widget container which is this format: id_<field-name>_jsonform.

E.g., if your model’s JSONField is called “my_field”, then the container id will be id_my_field_jsonform.

You can also do Right-click > Inspect element on the form widget to view the ID of the container.

var form = reactJsonForm.getFormInstance('id_my_field_jsonform');

formInstance.addEventListener(event, callback)

Use this function to add a callback function for an event. It will be called every time the event occurs.

The callback will receive an object containing these keys:

  • data: The data of the widget

  • schema: The schema of the widget

  • prevData: Previous data (before the event)

  • prevSchema: Previous schema (before the event)

function onChangeHandler(e) {
    // do something ...
}

var form = reactJsonForm.getFormInstance('id_my_field_jsonform');

form.addEventListener('change', onChangeHandler);

formInstance.update(config)

Use this function to update the schema or the data of the widget.

The config is a JavaScript object (dict) which looks like this:

var config = {
    schema: ...,
    data: ...,
}

form.update(config);

Important

If you call the update function inside an event handler callback, it is important that you call it conditionally. Otherwise, it might lead to an infinite loop.

For example, call this function if the current data (data) and the previous data (prevData) are not the same. This way you can avoid the infinite loop.

Practical example

Updating choices dynamically: Let’s look at an example where there are two select inputs and choices of the second input depends on the first input.

Interactive Demo

In the following demo, Vehicle input’s choices and helpText will change dynamically depending upon the value of the Category input.

Schema

The schema for this demo:

{
    'type': 'object',
    'title': 'Mode of transportation',
    'keys': {
        'category': {
            'type': 'string',
            'choices': ['Land', 'Water', 'Air']
        },
        'vehicle': {
            'type': 'string',
            'choices': [] # vehicle choices will be added dynamically
        }
    }
}

Relevant JavaScript code

Following is the code which is used in the demo above:

// my-script.js

window.addEventListener('load', function() {
    /* We want to run this code after all other scripts have been loaded */

    if (window.reactJsonForm) {
        /* We put this inside a condition because
         * we only want it to run on those pages where
         * django-jsonform widget is loaded
         */
        var form = reactJsonForm.getFormInstance('id_my_field_jsonform');
        form.addEventListener('change', onJsonFormChange);
    }
});


var vehicleChoiceMap = {
    'Land': ['Car', 'Bus', 'Train'],
    'Water': ['Ship', 'Boat', 'Submarine'],
    'Air': ['Aeroplane', 'Rocket'],
};


function onJsonformChange(e) {
    var data = e.data; // current data after
    var prevData = e.prevData; // previous data (before this event)

    var schema = e.schema; // current schema
    var prevSchema = e.prevSchema; // previous schema (before this event)

    if (!data.category) {
        /* no category selected yet, exit the function */
        return;
    }

    if (data.category === prevData.category) {
        /* category hasn't changed, no need to update choices */
        return;
    }

    schema.keys.vehicle.choices = vehicleChoiceMap[data.category];
    schema.keys.vehicle.helpText = "Select " + data.category + " vehicle";
    data.vehicle = ''; // reset previously selected vehicle

    form.update({
        schema: schema,
        data: data
    })
}

Loading your custom JS file on the admin page

You can use the Media class to load your custom JS files in the admin page.

Quickest way is via your admin class:

# models.py

class MyAdmin(admin.ModelAdmin):
    ...
    class Media:
        js = ('path/to/my-script.js',)

There are other ways as well (and perhaps more suitable in certain cases) for loading your custom files, such as by subclassing the widget.

See also

Form Assets (the Media class)

Django’s documentation on the Media class.