## Page, Container, Component
AutoConnectAux is the container for a custom Web page, AutoConnectElement is the component of a page. AutoConnectElements must be contained in AutoConnectAux object. (ie. they are the elements displayed on the custom Web page.) Then AutoConnect makes an AutoConnectAux to a page.
AutoConnectElements declared in sketch must be programmed to add to AutoConnectAux one after another. Elements are automatically included in AutoConnectAux by AutoConnect if you load it from the JSON document. In either method, it is common to use the function of AutoConnectAux to access an element with a sketch.
## Handing AutoConnectElements with the Sketches
The AutoConnectAux class has several functions to manipulate AutoConnectElements. The functions can add, delete, retrieve elements, and get and set values.
### Add AutoConnectElements to the AutoConnectAux object
To add AutoConnectElment(s) to an AutoConnectAux object, use the add function.
```cpp
void AutoConnectAux::add(AutoConnectElement& addon)
```
```cpp
void AutoConnectAux::add(AutoConnectElementVT addons)
```
The add function adds the specified AutoConnectElement to AutoConnectAux. The AutoConnectElementVT type is the [*std::vector*](https://en.cppreference.com/w/cpp/container/vector) of the [*reference wrapper*](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper) to AutoConnectElements, and you can add these elements in bulk by using the [*list initialization*](https://en.cppreference.com/w/cpp/language/list_initialization) with the Sketch.
```cpp
typedef std::vector> AutoConnectElementVT;
```
AutoConnectElements contained in AutoConnectAux object are uniquely identified by name. When adding an AutoConnectElement, if an element with the same name already exists in the AutoConnectAux, checking the type, and if it is the same, the value will be replaced. If another type of AutoConnectElement exists with the same name, that add operation will be invalid.[^1] In the following example, AutoConnectButton `button` addition will invalid because `hello` with the same name already exists as AutoConnectText.
[^1]: The valid scope of the name is within an AutoConnectAux.
```cpp hl_lines="3"
AutoConnectAux aux;
AutoConnectText text("hello", "hello, world");
AutoConnectButton button("hello", "hello, world", "alert('Hello world!')"); // This is invalid.
aux.add({ text, button });
```
Similarly this, the uniqueness of the name is also necessary within the JSON document
```json hl_lines="12"
{
"name" : "aux",
"uri" : "/aux",
"menu" : true,
"element" : [
{
"name": "hello",
"type": "ACText",
"value": "hello, world"
},
{
"name": "hello",
"type": "ACButton",
"value": "hello, world",
"action": "alert('Hello world!')"
}
]
}
```
!!! note "Load all elements from JSON document"
If you load all AutoConnectElements from JSON document into AutoConnect, you do not need to sketch the population process of the AutoConnectElements. It is managed by the AutoConnect library automatically.
### Get AutoConnectElement from the AutoConnectAux
To retrieve an element from AutoConnectAux, use the getElement or getElements function. Normally, the getElement is needed when accessing the value of AutoConnectElement in the Sketch.
```cpp
AutoConnectElement* AutoConnectAux::getElement(const String& name)
```
```cpp
T& AutoConnectAux::getElement(const String& name)
```
```cpp
AutoConnectElementVT* AutoConnectAux::getElements(void)
```
The [**getElement**](apiaux.md#getelement) function returns an AutoConnectElement with the specified name as a key. When you use this function, you need to know the type of AutoConnectElement in advance and specify its type to an argument of the getElement. A type of can be specified as follows.
```cpp
AutoConnectButton& AutoConnectAux::getElement(const String& name)
AutoConnectCheckbox& AutoConnectAux::getElement(const String& name)
AutoConnectElement& AutoConnectAux::getElement(const String& name)
AutoConnectFile& AutoConnectAux::getElement(const String& name)
AutoConnectInput& AutoConnectAux::getElement(const String& name)
AutoConnectRadio& AutoConnectAux::getElement(const String& name)
AutoConnectSelect& AutoConnectAux::getElement(const String& name)
AutoConnectSubmit& AutoConnectAux::getElement(const String& name)
AutoConnectText& AutoConnectAux::getElement(const String& name)
```
To retrieve an AutoConnectElement by specifying its type, use the following method.
```cpp
AutoConnectAux aux;
aux.load("SOME_JSON_DOCUMENT");
// Retrieve the pointer of the AutoConnectText
AutoConnectText* text = reinterpret_cast(aux.getElement("TEXT_ELEMENT_NAME"));
// Retrieve the reference of the AutoConnectText
AutoConnectText& text = aux.getElement("TEXT_ELEMENT_NAME");
```
The AutoConnectElement type behaves as a variant of other element types. Therefore use cast or template to convert to actual type as above. In the Sketch, you access the real type of AutoConnectElement after casting it and storing into the variable.
```cpp
const String auxJson = String("{\"title\":\"Page 1 title\",\"uri\":\"/page1\",\"menu\":true,\"element\":[{\"name\":\"caption\",\"type\":\"ACText\",\"value\":\"hello, world\"}]}");
AutoConnect portal;
portal.load(auxJson);
AutoConnectAux* aux = portal.aux("/page1"); // Identify the AutoConnectAux instance with uri
AutoConnectText& text = aux->getElement("caption"); // Cast to real type and access members
Serial.println(text.value);
```
You can also use the [operator **`[]`** of AutoConnectAux](apiaux.md#operator) as another way to get the desired element. An operator **`[]`** is a shortcut for [getElement](apiaux.md#getelement) function with the reference casting and makes simplify the Sketch code and treats like an array with the elements placed on a custom Web page. Its argument is the name of the element to be acquired similarly to getElement function. In the Sketch, by combining the [**AutoConnectElement::as**](apielements.md#ast62) function with the operator `[]`, you can access the AutoConnectElements reference according to its actual type. For example, the following sketch code returns the same as a reference of AutoConnectText element as the `caption`.
```cpp hl_lines="4 5"
AutoConnect portal;
portal.load(auxJson);
AutoConnectAux& aux = *portal.aux("/page1");
AutoConnectText& text1 = aux.getElement("caption");
AutoConnectText& text2 = aux["caption"].as();
```
!!! note "Need cast to convert to the actual type"
An operator `[]` returns a reference of an AutoConnectElement. It is necessary to convert the type according to the actual element type with [AutoConnectElement::as](apielements.md#ast62) function.
```cpp
AutoConnectButton& AutoConnectElement::as()
AutoConnectCheckbox& AutoConnectElement::as()
AutoConnectElement& AutoConnectElement::as()
AutoConnectFile& AutoConnectElement::as()
AutoConnectInput& AutoConnectElement::as()
AutoConnectRadio& AutoConnectElement::as()
AutoConnectSelect& AutoConnectElement::as()
AutoConnectSubmit& AutoConnectElement::as()
AutoConnectText& AutoConnectElement::as()
```
To get all the AutoConnectElements in an AutoConnectAux object use the [**getElements**](apiaux.md#getelements) function. This function returns the vector of the reference wrapper as **AutoConnectElementVT** to all AutoConnectElements registered in the AutoConnectAux.
```cpp
AutoConnectElementVT& AutoConnectAux::getElements(void)
```
### Enable AutoConnectElements during the Sketch execution
AutoConnectElemets have an enable attribute to activate its own HTML generation. Sketches can change the HTMLization of their elements dynamically by setting or resetting the enable value. An element whose the enable attribute is true will generate itself HTML and place on the custom Web page. And conversely, it will not generate the HTML when the value is false.
For example, to enable the submit button only when the ESP module is connected to the access point in STA mode, you can sketch the following:
```cpp hl_lines="30 31 32 33"
#include
#include
#include
static const char AUX[] PROGMEM = R("
{
"name" : "aux",
"uri" : "/aux",
"menu" : true,
"element" : [
{
"name": "input",
"type": "ACInput",
"label": "Input"
},
{
"name": "send",
"type": "ACSubmit",
"uri": "/send"
}
]
}
");
AutoConnect portal;
AutoConnectAux page;
String onPage(AutoConectAux& aux, PageArgument& args) {
AutoConnectSubmit& send = aux["send"].as();
if (WiFi.isConnected())
send.enable = (WiFi.getMode() == WIFI_STA);
else
send.enable = false;
return String();
}
void setup() {
page.load(AUX);
page.on(onPage);
portal.join(page);
portal.begin();
}
void loop() {
portal.handleClient();
}
```
!!! hint "Desirable to set or reset the enable attribute in the page handler"
The enable attribute can be set at any time during the Sketch execution. The page handler with the [AC_EXIT_AHEAD](apiaux.md#on) option is sure to handle it.
## Loading & saving AutoConnectElements with JSON
AutoConnect supports reading the custom Web page definitions written in JSON and also supports loading and saving of AutoConnectAux or AutoConnectElements. In both cases, the target object is a [JSON document for AutoConnect](acjson.md). However, it can not save all AutoConnectElements contained in the page as a custom Web page. (ie. AutoConnectAux)
### Loading AutoConnectAux & AutoConnectElements with JSON
To load a JSON document as AutoConnectAux use the [**AutoConnect::load**](api.md#load) function and load the JSON document of each AutoConnectElement using the [**AutoConnectAux::loadElement**](apiaux.md#loadelement) function. Although the functions of both are similar, the structure of the target JSON document is different.
The [AutoConnect::load](apiaux.md#load) function loads the entire AutoConnectAux and creates both the AutoConnectAux instance and each AutoConnectElement instance. A single JSON document can contain multiple custom Web pages. If you write JSON of AutoConnectAux as an array, the load function generates all the pages contained in that array. Therefore, it is necessary to supply the JSON document of AutoConnectAux as an input of the load function and must contain the elements described section [*JSON document structure for AutoConnectAux*](acjson.md#json-document-structure-for-autoconnectaux).
The [AutoConnectAux::loadElement](apiaux.md#loadelement) function loads the elements individually into an AutoConnectAux object. The structure of its supplying JSON document is not AutoConnectAux. It must be a [JSON structure for AutoConnectElement](acjson.md#json-object-for-autoconnectelements), but you can specify an array.
```cpp hl_lines="49 55"
// AutoConnectAux as a custom Web page.
const char page[] PROGMEM = R"raw(
{
"title": "Settings",
"uri": "/settings",
"menu": true,
"element": [
{
"name": "server",
"type": "ACInput",
"label": "Server"
},
{
"name": "set",
"type": "ACSubmit",
"value": "SET",
"uri" : "/set"
}
]
}
)raw";
// Additional AutoConnectElements.
const char addons[] PROGMEM = R"raw(
[
{
"name": "notes",
"type": "ACText",
"value": "An update period as the below optionally."
},
{
"name": "period",
"type": "ACRadio",
"value": [
"30 sec.",
"60 sec.",
"180 sec."
],
"arrange": "vertical",
"checked": 1
}
]
)raw";
AutoConnect portal;
AutoConnectAux* auxPage;
// Load a custom Web page.
portal.load(page);
// Get a '/settings' page
auxPage = portal.aux("/settings");
// Also, load only AutoConnectRadio named the period.
auxPage->loadElement(addons, "period");
// Retrieve a server name from an AutoConnectText value.
AutoConnectText& serverName = auxPage->getElement("server");
Serial.println(serverName.value);
```
### Saving AutoConnectElements with JSON
To save the AutoConnectAux or the AutoConnectElement as a JSON document, use the [AutoConnectAux::saveElement](apiaux.md#saveelement) function. It serializes the contents of the object based on the type of the AutoConnectElement. You can persist a serialized AutoConnectElements as a JSON document to a stream.
```cpp
// Open a parameter file on the SPIFFS.
SPIFFS.begin();
FILE param = SPIFFS.open("/param", "w");
// Save elements as the parameters.
auxPage->saveElement(param, { "server", "period" });
// Close a parameter file.
param.close();
SPIFFS.end();
```
The example above saves `server` and `period` elements from the AutoConnectAux object as mentioned above to the `/param` file on SPIFFS. Its JSON document of AutoConnectElements saved by its code looks like this:
```json
[
{
"name": "server",
"type": "ACInput",
"value": "An inputted server name",
"label": "Server",
"placeholder": ""
},
{
"name": "period",
"type": "ACRadio",
"value": [
"30 sec.",
"60 sec.",
"180 sec."
],
"arrange": "vertical",
"checked": 2
}
]
```
Above JSON document can be loaded as it is into a custom Web page using the loadElement function. The loadElement function also loads the value of the element, so the saved value can be restored on the custom Web page.
## Custom field data handling
A sketch can access variables of AutoConnectElements in the custom Web page. The value entered into the AutoConnectElements on the page is stored in the member variable of each element by AutoConnect whenever GET/POST transmission occurs.
The following diagram shows the flow of the input values of a custom Web page into a sketch and is the basis for actions to manipulate the values of custom Web pages using sketches.
### Where to pick up the values
A sketch composed of handlers can receive the value of AutoConnectElements entered in a custom Web page after sending, but that handler is different from the page where the value was entered. It is necessary to be aware that can accept the entered values by the next page handler after the transition.
Usually, two ways to retrieve entered values we have. One is to use the [ESP8266WebServer::arg](https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer#getting-information-about-request-arguments) (or WebServer::arg for ESP32) function in the [`on handler`](https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer#client-request-handlers) attached by ESP8266WebServer (WebServer w/ESP32 also).
```cpp hl_lines="33"
#include
#include
#include
static const char addonJson[] PROGMEM = R"raw(
{
"title": "Hello",
"uri": "/hello",
"menu": true,
"element": [
{
"name": "feels",
"type": "ACInput",
"label": "What's up?"
},
{
"name": "send",
"type": "ACSubmit",
"value": "Just it!",
"uri": "/feels"
}
]
}
)raw";
ESP8266WebServer webServer;
AutoConnect portal(webServer);
// Here, /feels handler
void feelsOn() {
// Retrieve the value of a input-box named "feels"
String feel = webServer.arg("feels");
// Echo back the value
String echo = "