---
title: "Inputs Layout and Forms"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Inputs Layout and Forms}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, echo=FALSE, message=FALSE}
library(bslib)
```

Since {shinyMobile} 2.0.0, the layout of inputs has been improved. It is recommended that multiple inputs are wrapped inside a `f7List()` to benefit from styling options such as `inset`, `strong`, `dividers`,and `outline`. Also introduced since 2.0.0 are the functions `f7Form()` and `updateF7Form()` to gather inputs in the same form and update them in batch or only selected ones.

## Inputs Layout

In your app you can have many different inputs. Most of the time these inputs are nicely displayed together so the users can make her/his selections. With the many styling options that Framework7 provides, it can be quite a hassle if you would have to style them all individually. Luckily, you don't have to! You can wrap them inside a `f7List()` to benefit from the styling options, styling them all at once (see below with the iOS skin):

```{r, eval=TRUE, echo=FALSE}
card(
  shinyMobile:::create_app_link(
    " ", # nolint
    "app",
    header = FALSE
  ),
  full_screen = TRUE,
  style = "width: 393px; margin: 0 auto; float: none;"
)
```
<div class="text-center mt-4">
<a class="btn btn-primary" data-bs-toggle="collapse" href="#inputlist" role="button" aria-expanded="false" aria-controls="singleLayout">
Code
</a>
</div>

<div class="collapse" id="inputlist">
```{r, eval = FALSE}
library(shiny)
library(shinyMobile)

shinyApp(
  ui = f7Page(
    options = list(dark = FALSE, theme = "ios"),
    title = "Inputs Layout",
    f7SingleLayout(
      navbar = f7Navbar(
        title = "Inputs Layout",
        hairline = FALSE
      ),
      f7List(
        inset = TRUE,
        dividers = TRUE,
        strong = TRUE,
        outline = FALSE,
        f7Text(
          inputId = "text",
          label = "Text input",
          value = "Some text",
          placeholder = "Your text here"
        ),
        f7TextArea(
          inputId = "textarea",
          label = "Text area input",
          value = "Some text",
          placeholder = "Your text here"
        ),
        f7Select(
          inputId = "select",
          label = "Make a choice",
          choices = 1:3,
          selected = 1
        ),
        f7AutoComplete(
          inputId = "myautocomplete",
          placeholder = "Some text here!",
          openIn = "dropdown",
          label = "Type a fruit name",
          choices = c(
            "Apple", "Apricot", "Avocado", "Banana", "Melon",
            "Orange", "Peach", "Pear", "Pineapple"
          )
        ),
        f7Toggle(
          inputId = "toggle",
          label = "Toggle me"
        ),
        f7Picker(
          inputId = "picker",
          placeholder = "Some text here!",
          label = "Picker Input",
          choices = c("a", "b", "c"),
          options = list(sheetPush = TRUE)
        ),
        f7DatePicker(
          inputId = "date",
          label = "Pick a date",
          value = Sys.Date()
        ),
        f7ColorPicker(
          inputId = "mycolorpicker",
          placeholder = "Some text here!",
          label = "Select a color"
        )
      )
    )
  ),
  server = function(input, output) {
  }
)
```
</div>

By default inputs list is displayed with stacked labels. Stacked labels always appear on top of the input.

<br>

The following inputs are supported: 

- `f7Text()`
- `f7TextArea()`
- `f7Password()`
- `f7Select()`
- `f7SmartSelect()`
- `f7AutoComplete()`
- `f7Stepper()`
- `f7Toggle()`
- `f7Picker()`
- `f7DatePicker()`
- `f7ColorPicker()`

<br>

This doesn't mean you can't use other inputs, but they may look a bit off. In this case you can take them out of `f7List()` and style them manually with the available options in the input. For example, `f7CheckboxGroup()` and `f7Radio()` are not supported in `f7List()` but can be styled to look similar:

```{r, eval=TRUE, echo=FALSE}
card(
  shinyMobile:::create_app_link(
    " ", # nolint
    "app",
    header = FALSE
  ),
  full_screen = TRUE,
  style = "width: 393px; margin: 0 auto; float: none;"
)
```
<div class="text-center mt-4">
<a class="btn btn-primary" data-bs-toggle="collapse" href="#outsidelist" role="button" aria-expanded="false" aria-controls="singleLayout">
Code
</a>
</div>

<div class="collapse" id="outsidelist">
```{r, eval = FALSE}
library(shiny)
library(shinyMobile)

shinyApp(
  ui = f7Page(
    options = list(dark = FALSE, theme = "ios"),
    title = "Inputs Layout",
    f7SingleLayout(
      navbar = f7Navbar(
        title = "Inputs Layout",
        hairline = FALSE
      ),
      f7List(
        inset = TRUE,
        dividers = TRUE,
        strong = TRUE,
        outline = FALSE,
        f7Text(
          inputId = "text",
          label = "Text input",
          value = "Some text",
          placeholder = "Your text here"
        ),
        f7TextArea(
          inputId = "textarea",
          label = "Text area input",
          value = "Some text",
          placeholder = "Your text here"
        ),
        f7Select(
          inputId = "select",
          label = "Make a choice",
          choices = 1:3,
          selected = 1
        ),
        f7AutoComplete(
          inputId = "myautocomplete",
          placeholder = "Some text here!",
          openIn = "dropdown",
          label = "Type a fruit name",
          choices = c(
            "Apple", "Apricot", "Avocado", "Banana", "Melon",
            "Orange", "Peach", "Pear", "Pineapple"
          )
        ),
        f7Stepper(
          inputId = "stepper",
          label = "My stepper",
          min = 0,
          color = "default",
          max = 10,
          value = 4
        ),
        f7Toggle(
          inputId = "toggle",
          label = "Toggle me"
        ),
        f7Picker(
          inputId = "picker",
          placeholder = "Some text here!",
          label = "Picker Input",
          choices = c("a", "b", "c"),
          options = list(sheetPush = TRUE)
        ),
        f7DatePicker(
          inputId = "date",
          label = "Pick a date",
          value = Sys.Date()
        ),
        f7ColorPicker(
          inputId = "mycolorpicker",
          placeholder = "Some text here!",
          label = "Select a color"
        )
      ),
      f7CheckboxGroup(
        inputId = "checkbox",
        label = "Checkbox group",
        choices = c("a", "b", "c"),
        selected = "a",
        style = list(
          inset = TRUE,
          dividers = TRUE,
          strong = TRUE,
          outline = FALSE
        )
      ),
      f7Radio(
        inputId = "radio",
        label = "Radio group",
        choices = c("a", "b", "c"),
        selected = "a",
        style = list(
          inset = TRUE,
          dividers = TRUE,
          strong = TRUE,
          outline = FALSE
        )
      )
    )
  ),
  server = function(input, output) {
  }
)
```
</div>

## Forms

Since {shinyMobile} 2.0.0, the functions `f7Form()` and `updateF7Form()` have been introduced to gather inputs in the same form and update them in batch or only selected ones. The form returns a list with all the inputs inside it, and you can access them by their `inputId`. 

<br>

In the below example this means you can gather all the values by simply calling `input$myform` and update them all at once by calling `updateF7Form()`:

```{r, eval=TRUE, echo=FALSE}
card(
  shinyMobile:::create_app_link(
    " ", # nolint
    "app",
    header = FALSE
  ),
  full_screen = TRUE,
  style = "width: 393px; margin: 0 auto; float: none;"
)
```
<div class="text-center mt-4">
<a class="btn btn-primary" data-bs-toggle="collapse" href="#forms" role="button" aria-expanded="false" aria-controls="singleLayout">
Code
</a>
</div>

<div class="collapse" id="forms">
```{r, eval = FALSE}
library(shiny)
library(shinyMobile)

shinyApp(
  ui = f7Page(
    f7SingleLayout(
      navbar = f7Navbar(title = "Inputs form"),
      f7Block(f7Button("update", "Click me")),
      f7BlockTitle("A list of inputs in a form"),
      f7List(
        inset = TRUE,
        dividers = FALSE,
        strong = TRUE,
        outline = FALSE,
        f7Form(
          id = "myform",
          f7Text(
            inputId = "text",
            label = "Text input",
            value = "Some text",
            placeholder = "Your text here",
            style = list(
              description = "A cool text input",
              outline = TRUE,
              media = f7Icon("house"),
              clearable = TRUE,
              floating = TRUE
            )
          ),
          f7TextArea(
            inputId = "textarea",
            label = "Text Area",
            value = "Lorem ipsum dolor sit amet, consectetur
              adipiscing elit, sed do eiusmod tempor incididunt ut
              labore et dolore magna aliqua",
            placeholder = "Your text here",
            resize = TRUE,
            style = list(
              description = "A cool text input",
              outline = TRUE,
              media = f7Icon("house"),
              clearable = TRUE,
              floating = TRUE
            )
          ),
          f7Password(
            inputId = "password",
            label = "Password:",
            placeholder = "Your password here",
            style = list(
              description = "A cool text input",
              outline = TRUE,
              media = f7Icon("house"),
              clearable = TRUE,
              floating = TRUE
            )
          ),
          f7Select(
            inputId = "select",
            label = "Select a number",
            choices = c(1, 2, 3),
            style = list(
              description = "A selection",
              outline = TRUE,
              media = f7Icon("house")
            )
          )
        )
      ),
      f7Block(verbatimTextOutput("form"))
    )
  ),
  server = function(input, output, session) {
    output$form <- renderPrint(input$myform)
    
    observeEvent(input$update, {
      updateF7Form(
        "myform",
        data = list(
          "text" = "New text",
          "textarea" = "New text area",
          "password" = "New password",
          "select" = 3
        )
      )
    })
  }
)
```
</div>

Since the `f7Form()` is wrapped inside a `f7List()`, it will look like a regular list of inputs. The difference is in the way the inputs are gathered and how they can be updated.

<br>

Currently, the following inputs supported for the form are: 

- `f7Text()`
- `f7TextArea()`
- `f7Password()`
- `f7Select()`

<br>

Having other types of inputs in your form might not looks as good, or it might not return the expected results.

