How to create a form and submit it to an API

On this section, you will find how to create a form and submit it to an API.

Introduction

For this tutorial, you’ll use some actions and APIs:

Actions

APIs

Despite the Server-Driven concept of working with components separatedly, it is possible to stream information to an API. Check out below:

Use example

On this example, use the TextInput and Button components to simulate the login screen.

Step 1: Create a login screen

Here, you have to signal to Beagle that it has to render on the screen two TextInputs and one Button. This will represent the login screen:

{
  "_beagleComponent_": "beagle:container",
  "children": [
    {
      "_beagleComponent_": "beagle:textInput",
      "placeholder": "Username"
    },
    {
      "_beagleComponent_": "beagle:textInput",
      "placeholder": "Password"
    },
    {
      "_beagleComponent_": "beagle:button",
      "text": "Login"
    }
  ]
}
Container(
     children = listOf(
                TextInput(placeholder = "Username"),
                TextInput(placeholder = "Password"),
                Button(text = "Login")
            )
        )

Step 2: Configure SetContext

Now use the SetContext action that alters a specific context on a screen. This is necessary to bring the screen to life and make the typed data on them sent to an API.

On this scenario, the context will keep the user name and password typed data, so this same data forwards to an API.

Alter this code to add this SetContext logic:

{
  "_beagleComponent_": "beagle:container",
  "children": [
    {
      "_beagleComponent_": "beagle:textInput",
      "value": "@{credentials.username}",
      "placeholder": "Username",
      "onChange": [
        {
          "_beagleAction_": "beagle:setContext",
          "contextId": "credentials",
          "value": "@{onChange.value}",
          "path": "username"
        }
      ]
    },
    {
      "_beagleComponent_": "beagle:textInput",
      "value": "@{credentials.password}",
      "placeholder": "Password",
      "onChange": [
        {
          "_beagleAction_": "beagle:setContext",
          "contextId": "credentials",
          "value": "@{onChange.value}",
          "path": "password"
        }
      ]
    },
    {
      "_beagleComponent_": "beagle:button",
      "text": "Login"
    }
  ],
  "context": {
    "id": "credentials",
    "value": {
      "username": "",
      "password": ""
    }
  }
}
data class Credentials(
  val username: String,
  val password: String
)

Container(
        context = ContextData(
             id = "credentials",
             value = Credentials(username = "",password = "")
            ),
         children = listOf(
             TextInput(
                  placeholder = "Username",
                  value = "@{credentials.username}",
                  onChange = listOf(
                      SetContext(
                          contextId = "credentials",
                          path = "username",
                          value = "@{onChange.value}"
                      )
                  )
              ),
              TextInput(
                  placeholder = "Password",
                  value = "@{credentials.password}",
                  onChange = listOf(
                      SetContext(
                           contextId = "credentials",
                           path = "password",
                           value = "@{onChange.value}"
                      )
                   )
                ),
               Button(text = "Login")
            )
        )

On this example, the onChange event of the TextInput is always called when the user types a new text in the input. Inside the onChange, there is an implicit context implicit context called onChange where the value is the last typed value by the user.

OnChange

In the context, the action SetContext performs in each character typed by the user. In SetContext, it is required the contextId, because it makes reference to the context that it will be altered, besides of the value that represents the new value, and the path that is the way inside the context that will be altered.

Path

It is the only optional parameter, in case it does not pass, the SetContext will alter the root context in order to make value the new value. On the example above, it is clear that you want to alter only the username and the password key in their respective SetContexts.

The context and expressions combination is of great potential because they can be implemented inside the Action you refer in the implicit context of whom performed the actions. You could see that in the onChange case, but it is possible to make a reference to other contexts inside an implicit context, then use multiple expressions.

Step 3: Send data to an API

You already have “saved” these context values so that on this step you can send it to an API through a request.

To finish the Login flow, you will now add an Action called SendRequest, that basically allows you to make a HTTP request, and on the onSuccess case, show an Alert welcoming the user.

{
  "_beagleComponent_": "beagle:container",
  "children": [
    {
      "_beagleComponent_": "beagle:textInput",
      "value": "@{credentials.username}",
      "placeholder": "Username",
      "onChange": [
        {
          "_beagleAction_": "beagle:setContext",
          "contextId": "credentials",
          "value": "@{onChange.value}",
          "path": "username"
        }
      ]
    },
    {
      "_beagleComponent_": "beagle:textInput",
      "value": "@{credentials.password}",
      "placeholder": "Password",
      "onChange": [
        {
          "_beagleAction_": "beagle:setContext",
          "contextId": "credentials",
          "value": "@{onChange.value}",
          "path": "password"
        }
      ]
    },
    {
      "_beagleComponent_": "beagle:button",
      "text": "Login",
      "onPress": [
        {
          "_beagleAction_": "beagle:sendRequest",
          "url": "http://beagle.free.beeceptor.com/login",
          "method": "POST",
          "headers":{
               "Content-Type":"application/json"
          },
          "data": {
            "username": "@{credentials.username}",
            "password": "@{credentials.password}",
            "authType": "login"
          },
          "onSuccess": [
            {
              "_beagleAction_": "beagle:alert",
              "title": "You are logged-in",
              "message": "@{onSuccess.data.message}"
            }
          ]
        }
      ]
    }
  ],
  "context": {
    "id": "credentials",
    "value": {
      "username": "",
      "password": ""
    }
  }
}
data class Credentials(
  val username: String,
  val password: String
)

data class RequestCredentials(
  val username: String,
  val password: String,
  val authType: String
)

Container(
        context = ContextData(
            id = "credentials",
            value = Credentials(username = "", password = "")
        ),
        children = listOf(
            TextInput(
                placeholder = "Username",
                value = "@{credentials.username}",
                onChange = listOf(
                    SetContext(
                        contextId = "credentials",
                        path = "username",
                        value = "@{onChange.value}"
                    )
                )
            ),
            TextInput(
                placeholder = "Password",
                value = "@{credentials.password}",
                onChange = listOf(
                    SetContext(
                        contextId = "credentials",
                        path = "password",
                        value = "@{onChange.value}"
                    )
                )
            ),
            Button(
                text = "Login",
                onPress = listOf(
                    SendRequest(
                        url = "http://beagle.free.beeceptor.com/login",
                        method = RequestActionMethod.POST,
                        headers = mapOf(
                            "Content-Type" to "application/json"
                        ),
                        data = RequestCredentials(
                          username = "@{credentials.username}",
                          password = "@{credentials.password}",
                          authType = "login"
                        ),
                     onSuccess = listOf(
                       Alert(
                         title = "You are logged-in",
                         message = "@{onSuccess.data.message}"
                     )
                 )
             )
           )
         )
      )
    )

When running this code, you have to fill in the fields and press the “Login” button.

After that, the onPress event will perform SendRequest sending all the data that are inside the context with the credentials ID.

When the SendRequest it is done, the response is finished, the onSuccess event will perform an Action Alert that it will show an alert with the returned data from the API.


Last modified September 17, 2021: Reviewed Android section (#773) (e4c75e98)