# Forms Engine

## Simplifying Complex Data Input

Building robust and user-friendly forms is often a significant challenge in web development. Traditional approaches can
lead to complex state management, difficult validation, and performance bottlenecks, especially with large or dynamic
forms. The Neo.mjs Forms Engine is designed from the ground up to simplify these complexities, offering a powerful,
declarative, and highly efficient solution for all your data input needs.

### Forms Include a State-Provider: Effortless Data Management

One of the most compelling features of the Neo.mjs Forms Engine is its integrated state management. You don't need to
manually define a separate state tree or connect external state management libraries. Instead, the form itself acts as
a state provider, automatically managing the data for its fields.

This is achieved by simply using namespaces within the `name` attribute of each field. The form engine intelligently
structures your data based on these names, providing a clean, hierarchical data object.

**Benefit**: This significantly reduces boilerplate code and simplifies data flow. Developers can focus on defining the
form structure and validation rules, rather than wrestling with data synchronization. For businesses, this means faster
development cycles and fewer bugs related to data handling.

```javascript live-preview
import Button        from '../button/Base.mjs';
import FormContainer from '../form/Container.mjs';
import TextField     from '../form/field/Text.mjs';

class MainView extends FormContainer {
    static config = {
        className: 'Benefits.forms1.MainView',
        layout   : {ntype:'vbox', align:'start'},
        
        items: [{
            module   : TextField,
            labelText: 'Firstname',
            name     : 'user.firstname',
            value    : 'John'
        }, {
            module   : TextField,
            labelText: 'Lastname',
            name     : 'user.lastname',
            value    : 'Doe'
        }, {
            module : Button,
            handler: 'up.getFormValues',
            style  : {marginTop: '1em'},
            text   : 'Get Form Values'
        }]
    }

    async getFormValues(data) {
        const formValues = await this.getValues();
        // Logs {user: {firstname: 'John', lastname: 'Doe'}}
        Neo.Main.log({value: formValues})
    }
}
MainView = Neo.setupClass(MainView);
```

### Forms Can Be Validated Without Being Mounted: Flexible UI Design

Neo.mjs forms exist as a pure abstraction layer within JavaScript, decoupled from their DOM representation. This unique
capability allows forms to be validated and their values retrieved even if they are not currently mounted in the DOM.

**Benefit**: This is incredibly powerful for complex user interfaces, such as multi-step wizards, tabbed forms, or
forms with conditionally rendered sections. You can maintain the state and validate parts of a form that are not
currently visible, ensuring data integrity without the performance overhead of rendering unnecessary DOM elements.
For users, this translates to a smoother, more responsive experience, as the UI remains lightweight.

```javascript live-preview
import Button        from '../button/Base.mjs';
import Container     from '../container/Base.mjs';
import FormContainer from '../form/Container.mjs';
import TextField     from '../form/field/Text.mjs';

const myForm = Neo.create({
    module: FormContainer,
    items : [{
        module   : TextField,
        labelText: 'Firstname',
        name     : 'user.firstname',
        value    : 'John'
    }, {
        module   : TextField,
        labelText: 'Lastname',
        name     : 'user.lastname',
        value    : 'Doe'
    }]
});

class MainView extends Container {
    static config = {
        className: 'Benefits.forms2.MainView',
        layout   : {ntype:'vbox', align:'start'},
        
        items: [{
            module : Button,
            handler: 'up.getFormValues',
            text   : 'Get Form Values'
        }]
    }

    async getFormValues(data) {
        const formValues = await myForm.getValues();
        // Logs {user: {firstname: 'John', lastname: 'Doe'}}
        Neo.Main.log({value: formValues})
    }
}
MainView = Neo.setupClass(MainView);
```

### Nested Forms: Unprecedented Structural Flexibility

Unlike the limitations of HTML, where nesting `<form>` tags is not permitted, Neo.mjs allows for true nested forms.
This is achieved by mapping form containers to generic DOM nodes (e.g., `{module: FormContainer, tag: 'div'}`).

**Benefit**: This capability provides unparalleled structural flexibility, enabling you to build highly modular and
complex forms. You can validate or retrieve values from individual nested forms, or from the top-level form (which
includes all nested items), as needed. This promotes better organization of large forms, improves maintainability,
and allows for fine-grained control over validation and data submission. For complex business processes, this means
forms can accurately reflect intricate data relationships.

Inside the example preview, clear the user lastname via hitting the x-button.
Afterwards, click on the 3 buttons at the bottom and inspect the output inside the main window console carefully.

The main form will log:
```javascript readonly
{
    account: 'My Account',
    product: {brand: 'Tesla', name: 'Car'},
    user   : {firstname: 'John', lastname: null}
}
'isValid: false'
```

The user form will log:
```javascript readonly
{user: {firstname: 'John', lastname: null}}
'isValid: false'
```

The product form will log:
```javascript readonly
{product: {brand: 'Tesla', name: 'Car'}}
'isValid: true'
```

```javascript live-preview
import Button        from '../button/Base.mjs';
import Container     from '../container/Base.mjs';
import FormContainer from '../form/Container.mjs';
import TabContainer  from '../tab/Container.mjs';
import TextField     from '../form/field/Text.mjs';

class MainView extends FormContainer {
    static config = {
        className: 'Benefits.forms3.MainView',
        layout   : {ntype:'vbox', align:'stretch'},
        
        items: [{
            module       : TextField,
            flex         : 'none',
            labelPosition: 'inline',
            labelText    : 'Account',
            name         : 'account',
            value        : 'My Account'
        }, {
            module: TabContainer,
            items : [{
                module      : FormContainer,
                header      : {text: 'User'},
                itemDefaults: {module: TextField, labelPosition: 'inline'},
                layout      : {ntype:'vbox', align:'start'},
                reference   : 'user-form',
                tag         : 'div',

                items: [{
                    labelText: 'Firstname',
                    name     : 'user.firstname',
                    value    : 'John'
                }, {
                    labelText: 'Lastname',
                    name     : 'user.lastname',
                    required : true,
                    value    : 'Doe'
                }]
            }, {
                module      : FormContainer,
                header      : {text: 'Product'},
                itemDefaults: {module: TextField, labelPosition: 'inline'},
                layout      : {ntype:'vbox', align:'start'},
                reference   : 'product-form',
                tag         : 'div',

                items: [{
                    labelText: 'Name',
                    name     : 'product.name',
                    value    : 'Car'
                }, {
                    labelText: 'Brand',
                    name     : 'product.brand',
                    required : true,
                    value    : 'Tesla'
                }]
            }]
        }, {
            module      : Container,
            flex        : 'none',
            itemDefaults: {module: Button},
            layout      : {ntype: 'hbox'},

            items: [{
                handler: 'up.getMainFormValues',
                text   : 'Get Main Values'
            }, {
                handler: 'up.getUserFormValues',
                text   : 'Get User Values'
            }, {
                handler: 'up.getProductFormValues',
                text   : 'Get Product Values'
            }]
        }]
    }

    async getFormValues(form) {
        const formValues = await form.getValues();
        Neo.Main.log({value: formValues});

        const isValid = await form.validate();
        Neo.Main.log({value: `isValid: ${isValid}`})
    }

    async getMainFormValues(data) {
        await this.getFormValues(this)
    }

    async getProductFormValues(data) {
        await this.getFormValues(this.getReference('product-form'))
    }

    async getUserFormValues(data) {
        await this.getFormValues(this.getReference('user-form'))
    }
}
MainView = Neo.setupClass(MainView);
```

Bonus: Inspect the DOM Inside the `TabContainer`.
You will notice that only the active Tab is mounted inside the DOM.

1. We can still get field values of unmounted forms
2. We can still validate unmounted forms

### Nested Lazy-Loaded Forms: Optimizing Performance for Complex UIs

If you look closely at the `Button` handlers in the last example, you'll notice that `getValues()` and `validate()`
are both `async` methods. The reason for this is that `form.getFields()` itself is also asynchronous: it will
lazy-load (but not necessarily mount) missing fields when needed.

**Benefit**: This asynchronous, lazy-loading mechanism is crucial for optimizing the performance of complex forms.
Instead of loading all form fields and their associated logic upfront, Neo.mjs only loads what's necessary, when it's
needed. This results in significantly faster initial load times, reduced memory footprint, and a more responsive
application, especially for forms with many fields or conditional sections.

The lazy-loading use case is not easy to display inside the `LivePreview`, since it does rely on defining child modules
inside their own class files and dynamically importing them. However, the pattern is straightforward:

```javascript readonly
{
    module: TabContainer,
    items : [
        {module: () => import('./MyChildForm1.mjs')},
        {module: () => import('./MyChildForm2.mjs')}
    ]
}
```

This allows for highly modular and performant form structures, where even entire sections of a form can be loaded
on-demand, further enhancing the user experience and application efficiency.

## Conclusion: A Comprehensive Solution for Form Development

The Neo.mjs Forms Engine provides a comprehensive and intuitive solution for building forms of any complexity.
By offering integrated state management, the ability to validate unmounted forms, true nested forms, and intelligent
lazy-loading, Neo.mjs empowers developers to create highly performant, maintainable, and user-friendly data input
experiences. This translates directly into increased developer productivity and a superior end-user experience.
