JavaScript API
==============
.. versionadded:: 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 concern the widget.
``reactJsonForm.getFormInstance(id)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use this function to get an instance of the form widget.
The ``id`` is the ID of the widget container which looks like this: ``id__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.
.. code-block:: javascript
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)
.. code-block:: javascript
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:
.. code-block:: javascript
var config = {
schema: ...,
data: ...,
}
form.update(config);
.. important::
If you call the ``update`` function from a ``change`` event listener, 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.
``formInstance.getData()``
~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns the current data of the form instance.
``formInstance.getSchema()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns the current schema of the form instance.
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.
.. raw:: html
Schema
~~~~~~
The schema for this demo:
.. code-block:: python
{
'type': 'object',
'title': 'Mode of transportation',
'keys': {
'category': {
'type': 'string',
'choices': ['Land', 'Water', 'Air']
},
'vehicle': {
'type': 'string',
'choices': [] # vehicle choices will be added dynamically
}
}
}
JavaScript code
~~~~~~~~~~~~~~~
Following is the code which is used in the demo above:
.. code-block:: javascript
// 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
var prevData = e.prevData; // previous data (before this event)
var schema = e.schema; // current schema
var prevSchema = e.prevSchema; // previous schema (before this event)
var selectedCategory = data.category;
if (!selectedCategory) {
/* no category selected yet, exit the function */
return;
}
if (selectedCategory === prevData.category) {
/* category hasn't changed, no need to update choices */
return;
}
schema.keys.vehicle.choices = vehicleChoiceMap[selectedCategory];
schema.keys.vehicle.helpText = "Select " + selectedCategory + " 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:
.. code-block:: python
# 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.
.. seealso::
`Form Assets (the Media class) `__
Django's documentation on the ``Media`` class.