2.5.0 • Published 9 days ago

akvo-react-form v2.5.0

Weekly downloads
-
License
AGPL-3.0
Repository
github
Last release
9 days ago

Akvo React Form

Simple react component for building webforms. View Demo

Build Status Repo Size GitHub release NPM Npm package total downloads JavaScript Style Guide GitHub license

Feature set

FeatureDescription
Initial values
Question Group Description
Translations
Multiple Question Dependency
Rule based response validation
Save Datapoint
Computed field value
Clear response
Custom style
Tooltip
Extra component on Question
HTML Support on Question
Field Suffix / Prefix
Print
Download response to tabular format

Install

Using NPM

npm install --save akvo-react-form

Using Yarn

yarn add akvo-react-form

Supported Field Type

TypeDescription
inputInput
numberInputNumber
cascadeCascade Select
textTextArea
dateDate
optionOption
multiple_optionMultiple Select
treeTree Select
tableTable (Multiple Question)
autofieldAutofieled
imageImage
entityEntity cascade select

Example Usage

import React from 'react';
import 'akvo-react-form/dist/index.css'; /* REQUIRED */
import { Webform } from 'akvo-react-form';
import * as forms from './example.json';

const App = () => {
  const onChange = ({ current, values, progress }) => {
    console.log(progress);
  };
  const onFinish = (values, refreshForm) => {
    console.log(values);
  };
  return (
    <div className="full-width">
      <Webform
        forms={forms.default}
        onChange={onChange}
        onFinish={onFinish}
      />
    </div>
  );
};

export default App;

Refresh Form

If using the autosave parameter, a form refresh is required to remove traces of the previous fields. onFinish includes a function to do this, you also need to change the autosave parameter if the submission is successful. If not, the form refresh will clean up the current datapoint.

Example: https://github.com/akvo/akvo-react-form/blob/8da791c2eeda896ae5fdc84509f5c6a72b5d2fa7/example/src/App.js#L41-L46

API

Webform

PropsDescriptionTypeDefault
sidebarOption to show / hide sidebarBooleantrue
stickySticky header and sidebar (Not support for IE9)Booleanfalse
onFinishTrigger after submitting the form and verifying data successfullyfunction(values)-
onChangeTrigger after field value changedfunction({current,values,progress})-
onCompleteFailedTrigger when submit is clicked with blank required questionfunction(values, errorFields)-
submitButtonSettingSubmit Button SettingObject{loading: Boolean, disabled: Boolean} | undefined{}
extraButtonExtra Button Next to Submit ButtonReactComponent | undefined-
initialValueSet value by Form initializationArray[Initial Value] | undefinedArray[]
printConfigSupport survey print functionalityObject{showButton: Boolean, filename: String, hideInputType: Array"field type", header: ReactComponent} | undefined-
downloadSubmissionConfigSupport download submission to ExcelObject{visible: Boolean, filename: String, horizontal: Boolean} | undefined-
leftDrawerConfigShow left drawer with custom componentObject{visible: Boolean, title: String, Content: ReactComponent} | undefined-
autoSaveEnable auto save to IndexedDBautoSaveObject | undefined-
fieldIconsShow icon for input and number question typeBooleantrue
formRefSet react useRef for Form from hostReact useRefnull
languagesDropdownSettingLanguages Dropdown SettingObject{showLanguageDropdown: Boolean , languageDropdownValue: ISO 639-1 codes} | undefined{}
UITextUI localization custom paramObject{ISO 639-1 codes: {...translations}} | undefined{}
showSpinnerShow a loading spinner when seeding data in progressBooleanfalse

Properties

Translations (optional)

PropsDescriptionType
Unique{any}Object to be translatedObject{any}
languageLanguageEnumISO 693-1

Form (Root)

PropsDescriptionType
nameForm Name / TitleString
question_groupList of Question GroupArray[Question Group]
Unique{any}Cascade definition, can be any propertiesArray[Cascade]
languagesList of available languagesArray[enumISO 639-1] | undefined
defaultLanguageDefault active languageEnumISO 639-1] | undefined
translationsList of translationsArray[Translations] | undefined

Question Group

PropsDescriptionType
nameQuestion Group Name / TitleString
orderQuestion Group OrderInteger | undefined
descriptionQuestion Group DescriptionString | undefined
questionList of QuestionArray[Question]
translationsList of translationsArray[Translations] | undefined

Cascade (any)

Cascading select questions are sets of questions whose options depend on the response to a previous question. Cascade object should be pre-defined on the question definition root object itself.

PropsDescriptionType
valueCascade ValueUnique (Integer | String)
labelCascade LabelString
childrenChildren of current objectArray[Cascade] | undefined
translationsList of translationsArray[Translations] | undefined

Example:

{
  "name": "Community Culinary Survey 2021",
  "translations": [
    {
      "name": "Komunitas Kuliner Survey 2021",
      "language": "id"
    }
  ],
  "languages": ["en", "id"],
  "question_group": [
    {
      "name": "Registration",
      "order": 1,
      "translations": [
        {
          "name": "Registrasi",
          "language": "id"
        }
      ],
      "question": [
        {
          "id": 1,
          "name": "Location",
          "order": 1,
          "type": "cascade",
          "option": "administration",
          "required": true,
          "translations": [
            {
              "name": "Lokasi",
              "language": "id"
            }
          ]
        }
      ]
    }
  ],
  "cascade": {
    "administration": [
      {
        "value": 1,
        "label": "Jawa Barat",
        "children": [
          {
            "value": 1,
            "label": "Garut"
          }
        ]
      }
    ]
  }
}

Using API for Cascade

Cascading select also support for a chain API call for the cascade dropdown list.

PropsDescriptionType
endpointCascade APIString
initialInitial ParameterInteger | String | undefined
listObject name of arrayres.data?.[list] \| res.data | String | undefined

Example:

  "name": "Community Culinary Survey 2021",
  "question_group": [{
      "name": "Registration",
      "order": 1,
      "question": [{
          "id": 1,
          "name": "Location",
          "order": 1,
          "type": "cascade",
          "api": {
            "endpoint": "https://tech-consultancy.akvo.org/akvo-flow-web-api/cascade/seap/cascade-296940912-v1.sqlite/",
            "initial": 0,
            "list": false
          },
          "required": true
       }]
  }]
PropsDescriptionType
idCascade ValueUnique (Integer | String)
nameCascade LabelString

API Example : https://tech-consultancy.akvo.org/akvo-flow-web-api/cascade/seap/cascade-296940912-v1.sqlite/0

[
  {
    "code": "ACEH",
    "id": 47,
    "name": "ACEH",
    "parent": 0
  },
  {
    "code": "BALI",
    "id": 128,
    "name": "BALI",
    "parent": 0
  }
]

Entity

Entity cascade selection is a dropdown option that requires an API and depends on the selected parent question, by setting the extra field and API format as follows.

Extra Entity
PropsDescriptionType
typeSet to "entity" (required)String
nameEntity nameString
parentIdParent entity question idNumber
Entity API format
PropsDescriptionType
idEntity ValueUnique (Integer | String)
nameEntity LabelString
[
  {
    "id": 91,
    "name": "School - Bandung 1",
  },
  {
    "id": 92,
    "name": "School - Bandung 2",
  }
]

Example:

{
  "id": 67,
  "label": "School cascade",
  "name": "school_cascade",
  "type": "cascade",
  "required": false,
  "order": 7,
  "api": {
    "endpoint": "https://akvo.github.io/akvo-react-form/api/entities/1/"
  },
  "extra": {
    "type": "entity",
    "name": "School",
    "parentId": 5 // question id: 5 (eg: administration type of question)
  }
},

Question

PropsDescriptionType
idQuestion IDUnique (Integer | String)
orderQuestion OrderInteger | undefined
tooltipQuestion TooltipString | undefined
typeQuestion Typenumber | input | text | option | multiple_option | cascade | tree | autofilled | table | image
optionList of Option (for option type of question )Array[Option] | String (cascade object name, only for 'cascade' type) | undefined
columnsColumns of table (for table type question) questionArray[Columns] | undefined
dependencyList of Question DependencyArray[Dependency] | undefined
ruleQuestion rule to be validated (Only for 'number' type of question){min: Integer, max: Integer}
metaQuestion set to be used as data point nameBoolean | undefined
requiredSet field as requiredBoolean | undefined
requiredSignSet custom required field symbol/mark before question label. requiredSign content will show if required param set to trueReactComponent | String | undefined
partialRequiredSet a custom required rule for type cascade. Set true to fill without having to select all the cascade level options when the required param is trueBoolean | undefined
translationsList of translationsArray[Translations] | undefined
extraExtra ComponentArray[ExtraComponent] | Object[ExtraEntity]undefined
addonBeforeAddon before Field (only support for number and input type of question)ReactComponent | String | undefined
addonAfterAddon before Field (only support for number and input type of question)ReactComponent | String | undefined
allowOtherAllow other field (support for option and multiple_option type of question)Boolean | undefined
allowOtherTextText Replacement for allow other field (support for option and multiple_option type of question)String | undefined
checkStrategyThe way show selected item in box when question type is tree. Default: show checked treeNodes (just show parent treeNode), "children": show only children nodeparent | children | undefined
expandAllWhether to expand all treeNodes by default. Default: falseBoolean | undefined
fnFunction for autofilled type of questionAutofield Function | undefined
dataApiUrlApi data that returns pair of object and value for hintString | undefined
limitSet limit / maximum file size in Megabyte (MB) for image type of questionInteger | undefined
disabledDefine to disabled the question fieldBoolean | undefined

Autofield Function

Autofield data use Javascript function in 1 line

Extra Component

PropsDescriptionType
contentContent of the Extra ComponentReactComponent | String
placementPlacement for the Extra Componentbefore | after
translationsList of translationsArray[Translations] | undefined

Rule

Rule should be defined as object, currently we only support min max value for number type of question.

PropsType
minInteger | undefined
maxInteger | undefined
allowDecimalBoolean | undefined

Example:

{
  "id": 1,
  "name": "Weight",
  "order": 1,
  "type": "number"
  "required": true,
  "tooltip": {"text": "Information Text"},
  "rule": {"min": 5,"max": 10},
  "addonAfter": "Kilograms",
  "meta": true,
  "translations": [{
      "name": "Berat Badan",
      "language": "id"
      }
   ],
   "extra": [{
       "placement": "before",
       "content": "Extra Component before the question",
       "translations": [{
           "content": "Komponen Tambahan sebelum pertanyaan ini",
           "language": "id"
        }]
    }]
}

Dependency (Skip Logic)

If question has dependency, question will be hidden by default. The question will only shows when dependency question values matches with the dependency rules.

PropsDescriptionType
idQuestion IDInteger | String
optionsList of dependency options to be validated, for 'option' type of the dependency questionArrayString | undefined
minMinimum dependency value to be validate, for 'number' type of the dependency questionArrayString | undefined
maxMaximum dependency value to be validate, for 'number' type of the dependency questionArrayString | undefined
equalDependent answer is equal toInteger | String | undefined
notEqualDependent answer is not blank and not equal toInteger | String | undefined

Example:

{
  "id": 11,
  "name": "Where do you usually order Rendang from ?",
  "dependency": [
    {
      "id": 9,
      "options": ["Yes"]
    },
    {
      "id": 10,
      "min": 8
    }
  ],
  "order": 5,
  "type": "option",
  "option": [
    {
      "name": "Pagi Sore",
      "order": 1
    },
    {
      "name": "Any Rendang Restaurant",
      "order": 2,
      "translations": [
        {
          "name": "Restoran Rendang Manapun",
          "language": "id"
        }
      ]
    }
  ],
  "required": true,
  "translations": [
    {
      "name": "Dimana anda biasanya membeli Rendang?",
      "language": "id"
    }
  ]
}

Option

Option is valid only for option type of question

PropsDescriptionType
nameOption Name / LabelString
orderQuestion Group OrderInteger | undefined
translationsList of translationsArray[Translations] | undefined
colorColor of the optionString | undefined

Columns

Columns is valid only for table type of question

PropsDescriptionType
nameColumn / Question object keyString
typeColumn / Question Typenumber | input | text | option
labelColumn / Question LabelString
optionOption valueArray[Option] | undefined

Initial Value (optional)

PropsDescriptionType
questionQuestion IDUnique (Integer | String)
valueValue of the QuestionString | Integer | Object{lat,lng} | ArrayInteger | String | Date Format
repeatIndexRepeat Index in Repeated Question Group. Default: 0Integer | undefined

Example: Initial Value Example

Autofieled Object

PropsDescriptionType
fnStringString of functionString
multilineWether function is multiline or notBool | undefined
fnColorColor for the answer fieldObject

Example for fnString:

function () { return #1 / #2 }

OR

() => { return #1.includes("Test") ? #2 / #3 : 0 }

Example for fnColor:

{
  "Answer A": "#CCFFC4"
  "Answer B": "#FECDCD"
}

Prefix #N is use to indicate the value of question id N. Note that we don't use javascript eval to overcome the security issue, the function will be sanitized before it's executed.

Auto Save Object

PropsDescriptionType
formIdRequiredInteger
nameName for datapointString | undefined
buttonTextCustom text for save buttonString | undefined

Auto save object require formId when it's enabled. This will filter list of saved data for particular formId. To show the list of saved datapoint we can use dataStore.

Example:

import React, { useState, useEffect } from 'react'
import { dataStore } from 'akvo-react-form'

const DataList = () => {
  const [datapoint, setDatapoint] = useState([])

  useEffect(() => {
    const listData = dataStore.list(formId)
    listData.then((x) => {
      setDatapoint(x)
    })
  }, [])

  return (
    <table>{dataPoints.map((x, xi) => (
      <tr key={xi}>
        <td>
          {xi + 1}. {x.name}
        </td>
        <td>
            <button onClick={x.load}>
              Load
            </button>
            <button onClick={x.remove}>
              Delete
            </button>
          </Space>
        </td>
      </tr>
    ))}
  </table>)
}

Example Form Structure

Please check the Form Definition Example which contains all the current features of akvo-react-form.

License

AGPL-3.0 © akvo

2.4.9

9 days ago

2.5.0

9 days ago

2.4.5

11 days ago

2.4.4

12 days ago

2.4.7

11 days ago

2.4.6

11 days ago

2.4.8

11 days ago

2.4.1

12 days ago

2.4.0

13 days ago

2.4.3

12 days ago

2.4.2

12 days ago

2.3.9

14 days ago

2.3.8

15 days ago

2.3.7

15 days ago

2.3.6

16 days ago

2.3.5

16 days ago

2.3.4

18 days ago

2.3.3

2 months ago

2.3.2

2 months ago

2.3.0

2 months ago

2.3.1

2 months ago

2.2.9

2 months ago

2.2.8

2 months ago

2.2.7

5 months ago

2.2.5

8 months ago

2.2.6

8 months ago

2.2.1

12 months ago

2.2.3

12 months ago

2.2.2

12 months ago

2.2.0

1 year ago

2.1.9

1 year ago

2.1.8

1 year ago

2.1.7

1 year ago

2.1.6

1 year ago

2.0.9

1 year ago

2.1.2

1 year ago

2.1.1

1 year ago

2.1.4

1 year ago

2.1.3

1 year ago

2.1.5

1 year ago

2.1.0

1 year ago

2.0.7

1 year ago

2.0.6

1 year ago

2.0.8

1 year ago

1.6.4

2 years ago

1.4.6

2 years ago

1.6.3

2 years ago

1.4.5

2 years ago

1.6.2

2 years ago

1.4.4

2 years ago

1.6.1

2 years ago

1.4.3

2 years ago

1.6.0

2 years ago

1.4.2

2 years ago

1.4.1

2 years ago

1.4.0

2 years ago

2.0.3

2 years ago

2.0.2

2 years ago

2.0.5

1 year ago

2.0.4

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.5.9

2 years ago

1.5.8

2 years ago

1.5.7

2 years ago

1.3.9

2 years ago

1.5.6

2 years ago

1.3.8

2 years ago

1.5.5

2 years ago

1.3.7

2 years ago

1.5.4

2 years ago

1.3.6

2 years ago

1.5.3

2 years ago

1.3.5

2 years ago

1.5.2

2 years ago

1.3.4

2 years ago

1.5.1

2 years ago

1.3.3

2 years ago

1.5.0

2 years ago

1.6.9

2 years ago

1.6.8

2 years ago

1.6.7

2 years ago

1.4.9

2 years ago

1.6.6

2 years ago

1.4.8

2 years ago

1.6.5

2 years ago

1.4.7

2 years ago

1.2.7

2 years ago

1.2.6

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.3.2

2 years ago

1.2.3

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.2-alpha

2 years ago

1.2.2-alpha.2

2 years ago

1.0.9

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.0.8

3 years ago

1.0.7

3 years ago

1.0.6

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago