Skip to content

5.1. Building and Obtaining Data form a Form

Elly Kitoto edited this page Jul 25, 2020 · 5 revisions

Building the Form

Neat Form parses the JSON form provided from the Android Assets directory into a model that it uses to render the views. The supported views are registered first before the form is built. Once the views have been created as children to the the RootView they are then passed to the FormBuilder.

You can override the supported views with your own implementation(s) if the features provided out of the box by neat form do not suffice. However one thing to note is that you can only extend the classes that implement ViewBuilder but not the NFormView classes.

The views are rendered in 2 ways.

  1. Using the default vertical LinearLayout - Views are rendered as per the order they are defined on the JSON form one on top of the other. (Suitable for low resolution devices; phones)

  2. Using custom layout - Alternatively you may still want to control of the way the UI should appear across various devices for instances tablets, Neat Form gives you the flexibility of doing this by passing a list of the xml layout files to use when rendering the views.

NOTE: For multi-step forms, the form will be rendered to the custom layout sequentially i.e. step one form will be rendered on the layout at position 0 of the views list and so on.

Forms can be generated in 2 ways, either by using JsonFormEmbedded or JsonFormStepper class. As their names suggest, JsonFormEmbedded is used when you want to render(embed) the form inside another view, whereas JsonFormStepper is used when you want to render the form using a stepper.

JsonFormBuilder class implements the interface FormBuilder. It has 2 constructors:

constructor(context: Context, fileSource: String, mainLayout: ViewGroup?)

and

 constructor(jsonString: String, context: Context, mainLayout: ViewGroup?)

with the former accepting a string of the path to the JSON file (usually stored in the assets directory) and the later accepting a string representation of the JSON form.

Creating embedded form

Code snippet for building an embedded form with/without using custom layout.

package com.nerdstone.neatform.form

import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import com.nerdstone.neatform.R
import com.nerdstone.neatformcore.domain.builders.FormBuilder
import com.nerdstone.neatformcore.form.json.JsonFormBuilder
import com.nerdstone.neatformcore.form.json.JsonFormEmbedded


class FormActivity : AppCompatActivity() {
   private lateinit var mainLayout: LinearLayout
   private var formBuilder: FormBuilder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.form_activity)

        mainLayout = findViewById(R.id.mainLayout)
       
        //sample_form_one.json is the path of the JSON file located in the assets directory
        formBuilder = JsonFormBuilder(this, "sample_form_one")      
        JsonFormEmbedded(formBuilder as JsonFormBuilder, mainLayout).buildForm()
        
        /**
        // Build form using custom layout provided (sample_one_form_custom_layout)
        
        val views = listOf<View>(layoutInflater.inflate(R.layout.sample_one_form_custom_layout, null)
        formBuilder = JsonFormBuilder(this, "sample_form_one")
        JsonFormEmbedded(formBuilder as JsonFormBuilder, mainLayout).buildForm(views)
        **/
    }
}

Creating stepper form

Code snippet for building a stepper form with/without using custom layout.

package com.nerdstone.neatform.form

import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity

import com.nerdstone.neatandroidstepper.core.widget.NeatStepperLayout

import com.nerdstone.neatform.R
import com.nerdstone.neatformcore.domain.builders.FormBuilder
import com.nerdstone.neatformcore.form.json.JsonFormBuilder
import com.nerdstone.neatformcore.form.json.JsonFormStepper


class FormActivity : AppCompatActivity() {
   private lateinit var neatStepperLayout: NeatStepperLayout
   private var formBuilder: FormBuilder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.form_activity)

        neatStepperLayout = findViewById(R.id.neatStepperLayout)
       
        //sample_form_one.json is the path of the JSON file located in the assets directory
        formBuilder = JsonFormBuilder(this, "sample_form_one")      
        JsonFormStepper(formBuilder as JsonFormBuilder, neatStepperLayout).buildForm()
        
        /**
        // Build form using custom layout provided (sample_one_form_custom_layout)
        
        val views = listOf<View>(layoutInflater.inflate(R.layout.sample_one_form_custom_layout, null)
        formBuilder = JsonFormBuilder(this, "sample_form_one")
        JsonFormStepper(formBuilder as JsonFormBuilder, neatStepperLayout).buildForm(views)
        **/
    }
}

The form builder will generate the views and place them inside the stepper as defined in the json.

Form Actions

For forms that are using the stepper library, they must implement the interface com.nerdstone.neatformcore.form.common.FormActions and implement the interface methods on the Activity/Fragment you are building the form on. The methods are callbacks used by the stepper library for instance methods called when you press next or previous buttons.

Pre-filling Form with data

You can set values to the form fields before building the form especially when you want to edit data that was collected previously. To achieve this call the method withFormData after instantiating the FormBuilder. The function takes a JSON string of the data plus you can optionally pass a set of the name of read only fields.

override fun onCreate(savedInstanceState: Bundle?) {
  formBuilder = JsonFormBuilder(this, "sample_form_one")?.also { 
  it.withFormData(
       """
          {
            "email_subscription": {
              "type": "CheckBoxNFormView",
              "value": {
                "email_subscription": "Subscribe to email notifications"
              },
              "visible": true
            },
            "no_prev_pregnancies": {
              "type": "NumberSelectorNFormView",
              "value": 1,
              "visible": true
            },
            "gender": {
              "type": "SpinnerNFormView",
              "value": {
                "value": "Female"
              }
            }
       }
      """, mutableSetOf("email_subscription"))
  }
  JsonFormEmbedded(formBuilder as JsonFormBuilder, mainLayout).buildForm()
}

NOTE: Form data MUST be in the format they were retrieved when the form was submitted (metadata is optional) . You can always set the field value programatically by updating the details map of the DataViewModel provided you have access to the Context.

Obtaining form data

You can retrieve data any time from the FormBuilder by invoking either of its two methods i.e. getFormDataAsJson() or getFormData(). The former returns a stringified JSON representation of the data retrieved from the form but also includes the form version, form_meta_data and form_name, whereas the later returns a map of all the fields in the form with their corresponding values.

You can get the metadata for the form separately via the getFormMetaData() method.

NOTE: You cannot retrieve data from the form when the form is invalid (when any field is invalid or when a required field is missing); an error dialog will be displayed instead.