Form control

The gameface-form-control is part of the Gameface custom components suite. As most of the components in this suite, it uses slots to allow dynamic content.

Installation

npm i coherent-gameface-form-control

Usage with UMD:

<script src="./node_modules/coherent-gameface-form-control/dist/form-control.production.min.js"></script>

This is all! Load the file in Gameface to see the gameface-form-control.

<gameface-form-control></gameface-form-control>

Usage with JavaScript:

If you wish to import the GamefaceFormControl using JavaScript you can replace the script tag with import statements like this:

import { GamefaceFormControl } from 'coherent-gameface-form-control';

or simply

import 'coherent-gameface-form-control';

Note that this approach requires a module bundler like Webpack or Rollup to resolve the modules from the node_modules folder.

Form control attributes

AttributeRequiredValuesDefault valueUsage
methodYesGET, POSTGETUsed to specify the HTTP method that will be used to send data when the form is submitted. If the attribute is not added or with no valid value the form won’t be published.
actionNoAny valid URL./Used to specify where the form will send the data. If the attribute is not added the data will be sent to the current page URL.

You can update the attributes using the DOM APIs:

document.querySelector('gameface-form-control').setAttribute('<attribute>', '<value>');

Where
<attribute> ::= method | action

Examples

  • <gameface-form-control method="GET" action="http://localhost:12345/login"></gameface-form-control> - Submitting this form will create a GET request with the form data and send it to the server that is available on http://localhost:12345/login.
  • <gameface-form-control method="POST"></gameface-form-control> - Submitting this form will create a POST request with the form data and send it to the current page location.
  • <gameface-form-control></gameface-form-control> - Submitting this form will produce a warning and the request will be aborted.

Form control events

Inline event handlers

EventValueUsage
onloadFunctionWill call the function that is added from the attribute’s value when the form request has been completed, whether with success or not.
onsubmitFunctionWill call the function that is added from the attribute’s value when the form is submitted and right before the request is made to the server.

Examples

Let us have the following functions:

function onRequestEnd(event) {
    console.log("Request response: ", event.detail.target.response)
}

function preventSubmit(event) {
    event.preventDefault();
}
  • <gameface-form-control onload="onRequestEnd(event)" method="GET" action="http://localhost:12345/login"></gameface-form-control> - onRequestEnd will log the response from the request.
  • <gameface-form-control onsubmit="preventSubmit(event)" method="GET" action="http://localhost:12345/login"></gameface-form-control> - preventSubmit will prevent form from making request to the server when the form is submitted.

Event handlers

EventUsage
loadendWill be triggered when the form request has completed, whether with success or not.
submitWill be triggered when the form is submitted and right before the request is made to the server.

Examples

Let us have the following form - <gameface-form-control id="form" method="GET" action="http://localhost:12345/login"></gameface-form-control>.

  • Log the response from the request.
const form = document.getElementById('form');
form.addEventListener('loadend', (event)=>{
    console.log("Request response: ",event.detail.target.response)
});
  • Prevent form from submitting.
const form = document.getElementById('form');
form.addEventListener('submit', (event) => {
    event.preventDefault();
});

Form control elements

Input

Text inputs

<input> element is supported from the gameface form control just when it is holding text values input with type text, password, email, etc.

The name attribute will be used to specify the form-data key and the value will be used to specify the form data value of the input.

Submit input

So far Gameface does not support input elements with the type submit although they can be defined in the DOM.

The form control will treat these elements like submit buttons and when they are clicked the form will be submitted.

Other inputs

Any other input elements with type range, color, date, etc. are not supported.

Example

<gameface-form-control method="GET" action="http://localhost:12345/login">
    <span>User name:</span>
    <input type="text" name="user" value="name"/>
    <span>Password:</span>
    <input type="password" name="password" value="pass"/>
    <input type="text" name="emptyInput"/>
    <input type="submit" name="submitButton" value="It is input not a button"/>
</gameface-form-control>

Clicking on the input with type submit will make a GET request to http://localhost:12345/login?user=name&password=pass&submitButton=It+is+input+not+a+button.

Notes

  • The data from <input type="submit"/> will be included in the request if this input is clicked.
  • The name attribute is required if you want your input to be included in the form data on submitting!

Select

Native <select> element is not supported by Gameface. However, there is a polyfill that transforms <select> into a working dropdown in the Gameface. That dropdown element - <custom-select> is supported by the form control component.

The polyfill is located inside the Gameface package - Samples/uiresources/Dropdown.

Example

<gameface-form-control method="GET" action="http://localhost:12345/">
    <span>Select city</span>
    <select name="city">
        <option id="Chongqing" name="Chongqing" value="Chongqing">Chongqing</option>
        <option id="Shanghai" name="Shanghai" value="Shanghai">Shanghai</option>
        <option id="Beijing" name="Beijing" value="Beijing">Beijing</option>
        <option id="Lagos" name="Lagos" value="Lagos">Lagos</option>
    </select>
</gameface-form-control>
<script src="Samples/uiresources/Dropdown/custom-select.js">

Textarea

<textarea> element is supported from the gameface form control.

The name attribute is required if you want the value to be included in the form data on submit.

The name attribute will be used to specify the form-data key and the value will be used to specify the form data value of the input.

Example

<gameface-form-control method="POST" action="http://localhost:12345/register">
    <span>User info:</span>
    <textarea name="info">Default value</textarea>
    <span>Additional info:</span>
    <textarea name="moreInfo"></textarea>
    <button type="submit">Submit form</button>
</gameface-form-control>

Clicking on the button will make a POST request to http://localhost:12345/register with the body {"info":"Default value"}. moreInfo won’t be included in the request body if its value is empty.

Button

<button> element is supported from the gameface form control.

To make a button that submits the form you need to add the type="submit" attribute to the button.

If a button has name and value attributes their values will be included in the form data on submit if this button is clicked.

Example

<gameface-form-control method="GET" action="http://localhost:12345/buttons">
    <button id="button-with-data" name="button" value="data" type="submit">Submit form</button>
    <button id="button-with-no-data" type="submit">Submit form</button>
</gameface-form-control>
  • Clicking on the button with id button-with-data will make a GET request to http://localhost:12345/buttons?button=data.
  • Clicking on the button with id button-with-no-data will make a GET request to http://localhost:12345/buttons.

Gameface checkbox

<gameface-checkbox> is a gameface component that represents a checkbox and it is supported by the gameface form control.

The name attribute is required if you want the checkbox to be included in the form data when submitted.

The value attribute is not required but if it is empty and the checkbox is checked then the value will be - on by default.

If the checkbox is checked then its name and value will be included in the form data on submit and vice versa if not.

Example

<gameface-form-control action="http://localhost:3000/interests" method="GET">
    <gameface-checkbox name="user-interests" value="music">
        <component-slot data-name="checkbox-background">
            <div class="guic-checkbox-background"></div>
        </component-slot>
        <component-slot data-name="checkbox-label">
            <span class="guic-checkbox-label">Music</span>
        </component-slot>
    </gameface-checkbox>
    <gameface-checkbox name="user-interests" value="coding">
        <component-slot data-name="checkbox-background">
            <div class="guic-checkbox-background"></div>
        </component-slot>
        <component-slot data-name="checkbox-label">
            <span class="guic-checkbox-label">Coding</span>
        </component-slot>
    </gameface-checkbox>
    <gameface-checkbox name="user-interests">
        <component-slot data-name="checkbox-background">
            <div class="guic-checkbox-background"></div>
        </component-slot>
        <component-slot data-name="checkbox-label">
            <span class="guic-checkbox-label">Nothing</span>
        </component-slot>
    </gameface-checkbox>
    <button type="submit">Submit</button>
</gameface-form-control>

Clicking on the submit button will make a GET request to http://localhost:3000/interests?user-interests=music&user-interests=coding&user-interests=on.

Unchecking the Nothing and Coding checkboxes and then submitting the form will make a GET request to http://localhost:3000/interests?user-interests=music.

Gameface radio group/button

<gameface-radio-group> is a gameface component that represents a group with radio buttons that lets the user choose one from all and it is supported by the gameface form control.

The name attribute is required if you want the radio group to be included in the form data when submitted.

The value attribute is not required for the radio-button element but if it is empty and the radio button is checked then the value will be - on by default.

Example

<gameface-form-control action="http://localhost:3000/options" method="POST">
    <span>Normal:</span>
    <gameface-radio-group name="option1">
        <radio-button checked value="1">1</radio-button>
        <radio-button value="2">2</radio-button>
        <radio-button value="3">3</radio-button>
    </gameface-radio-group>
    <span>No value:</span>
    <gameface-radio-group name="option2">
        <radio-button value="1">1</radio-button>
        <radio-button checked>2</radio-button>
        <radio-button value="3">3</radio-button>
    </gameface-radio-group>
    <button type="submit">Submit</button>
</gameface-form-control>

Clicking on the submit button will make a POST request to http://localhost:3000/options with body {"option1":1,"option2":"on"}.

Gameface switch

<gameface-switch> is a gameface component that represents a switch toggle button that lets the uses enable/disable the option and it is supported by the gameface form control.

The name attribute is required if you want the switch to be included in the form data when submitted.

The value attribute is not required for the switch element but if it is empty and the switch is enabled then the value will be - on by default.

Example

<gameface-form-control action="http://localhost:3000/options" method="POST">
    <span class="guic-checkbox-label">Normal</span>
    <gameface-switch name="option1" value="checked" type="text-inside">
        <component-slot data-name="switch-unchecked">No</component-slot>
        <component-slot data-name="switch-checked">Yes</component-slot>
    </gameface-switch>
    <span>No value:</span>
    <gameface-switch name="option2" type="text-inside">
        <component-slot data-name="switch-unchecked">No</component-slot>
        <component-slot data-name="switch-checked">Yes</component-slot>
    </gameface-switch>
    <button type="submit">Submit</button>
</gameface-form-control>

Enable both switch buttons.

Clicking on the submit button will make a POST request to http://localhost:3000/options with body {"option1":1,"option2":"on"}.

Gameface dropdown

<gameface-dropdown> is a gameface component that represents the native select menu and it is supported by the gameface form control.

The name attribute is required if you want the dropdown to be included in the form data when submitted.

The value attribute is not required for the dropdown option element but if it is empty and the options are selected then the value will be the text content of the option by default.

Example

<gameface-form-control action="http://localhost:3000/options" method="POST">
    <span class="guic-checkbox-label">Normal</span>
    <gameface-dropdown name="option1" class="gameface-dropdown-component" id="dropdown-default">
        <dropdown-option value="1" slot="option">One</dropdown-option>
        <dropdown-option value="2" slot="option">Two</dropdown-option>
    </gameface-dropdown>
    <span class="guic-checkbox-label">No values</span>
    <gameface-dropdown name="option2" class="gameface-dropdown-component" id="dropdown-default">
        <dropdown-option slot="option">One</dropdown-option>
        <dropdown-option slot="option">Two</dropdown-option>
    </gameface-dropdown>
    <button type="submit">Submit</button>
</gameface-form-control>

Clicking on the submit button will make a POST request to http://localhost:3000/options with body {"option1":1,"option2":"One"}.

Text Field

<gameface-text-field> is a component that allows you to use a text input of different types - text, email, password, number, etc. It supports validation. For example, if you create a text field with the type:

  • email - the built-in validation will check if the value has a @ symbol and it will show an error if does not.
  • url - the built-in validation will check a pattern as an attribute to the text field and its value should match this pattern. For example if the url should match certain domain name - <gameface-text-field type="url" pattern="mydomain.*">.
  • password - the built-in validation will check length through the minlength and maxlength attributes.
  • number - the built-in validation will check min and max attributes.
  • text, password, search - the built-in validation will check length through the minlength and maxlength attributes.

Example

<gameface-form-control style="position: absolute;top: 200px;">
    <gameface-text-field id="text" name="text" label="User name:" type="text" value="thisisvalid" minlength="5" maxlength="20"></gameface-text-field>
    <gameface-text-field id="url" name="url" pattern="https://.*" label="Website:" value="https://localhost:9090" type="url"></gameface-text-field>
    <gameface-text-field id="email" name="email" label="Email:" type="email" value="text-field@test.com"></gameface-text-field>
    <gameface-text-field id="number" name="number" label="Age:" type="number" min="15" max="200" step="10" value="30"></gameface-text-field>
    <button class="form-element" id="submit" type="submit">Login</button>
</gameface-form-control>

Validation

The form control supports validation. These are the attributes that you can use:

NamePurposeSupported Elements
requiredUsed to indicate that a value is required. Will show an error if the element doesn’t have value.Input, Textarea, Checkbox, Switch, Radio Button
minlengthUsed to indicate the minimum length of a text field.Input
maxlengthUsed to indicate the minimum length of a text field.Input
minUsed to indicate the minimum value of a number inputInput
maxUsed to indicate the maximum value of a number inputInput
patternUsed to specify a url pattern.TextField[type=“url”]
requiredUsed to specify that the element must have value.All form supported elements

Custom validation

The form control component supports custom validation as well. Its purpose is to customize the default methods for validation, error messages, or where to show them. The default methods for validating form are stored in a map where each method has a default message defined for it. These methods are checking if a form element meets the requirements to be valid that are defined by the attributes above. Here is a table describing each method name, its error, and its relevant form element attribute.

Default validator method nameError messageCorresponding attributeAdditional info
notAFormThis element is not part of a form.N/AThis validator validates if the element is part of the form control.
nameMissingThe element does not have a name attribute and will not be submittedN/AThis validator validates if a form element has valid name attribute set.
tooLongThe value is too long. Maximum length is ${element.getAttribute('maxlength')}.maxlength
tooShortThe value is too short. Minimal length is ${element.getAttribute('minlength')}.minlength
rangeOverflowThe value is too big. Maximum is ${element.getAttribute('max')}.max
rangeUnderflowThe value is too small. Minimum is ${element.getAttribute('min')}.min
valueMissingThe value is required.required
badURLPlease enter a valid URL. It should match the following pattern: /${element.pattern}/.N/AThis validator validates <gameface-text-field> component’s value when its type is url.
badEmailPlease enter a valid email. It should contain a @ symbol.N/AThis validator validates <gameface-text-field> component’s value when its type is email.

As you can see some validators have error messages that include some properties from the validated element. That is because each validator dynamically constructs the error messages using the currently validated form element.

Custom form validation methods

<gameface-form-control> component has some methods for making custom validation possible.

MethodArgumentsDescription
setCustomValidators(name: string, validators: ValidatorsConfig)Will set custom defined validators related to the form elements with the corresponding name attribute.
removeCustomValidator(name: string)Will remove any custom validators related to the form element with the corresponding name attribute.
removeCustomValidators(names: string[])Same as the removeCustomValidator but works with multiple names.
setCustomDisplayErrorElement(name: string, selector: string)Will change the default behavior of showing error messages. The name argument specifies the form element that will be modified. The selector specifies the element in which the error will be displayed.
removeCustomDisplayErrorElement(name: string)Remove the custom error message element previously added using setCustomDisplayErrorElement. The name argument specifies the form element. The default tooltip will be used instead for displaying errors.
removeCustomDisplayErrorElements(names: string[])Same as the removeCustomDisplayErrorElement method but works with multiple names.

ValidatorsConfig

It is an object that has the following type:

interface ValidatorsConfig {
    [ValidatorName: string]: {
        method?: (element: HTMLElement) => boolean | Promise<boolean>
        errorMessage?: (element: HTMLElement) => string
    }
}

With the ValidatorName key you define your custom validator name or you can use some of the default validator names to overwrite their behavior.

method is the function that is used to tell the form component if the currently validated element is valid. It receives that element and should return a boolean with the result about the validity of the element. You can use the async function to define the method property. To overwrite the default validators use ValidatorName that has the same name as the one you wish to change:

form.setCustomValidators('username', {
    valueMissing: { // will use this one, no the default
        method: (element) => !element.value,
        errorMessage: () => 'The username is required! '
    }
})

errorMessage is the function that constructs the message if the validation of the form element fails. It receives that element so you can extract its attributes and return a more specific error message. The function should return a string. If this property is added to ValidatorName that is some of the default ones will overwrite the default validation message.

form.setCustomValidators('username', {
    valueMissing: { 
        errorMessage: () => 'The username is required! ' // will use this error message, not the default that is "The value is required."
    }
})

Example

Let us have the following form defined

<gameface-form-control id="custom-validation-form">
    <gameface-text-field name="username" label="User name:" type="text" minlength="5" maxlength="20"></gameface-text-field>
    <span id="username-error"></span>
    <gameface-text-field name="url" label="Website:" type="url"></gameface-text-field>
    <gameface-text-field name="email" label="Email:" type="email"></gameface-text-field>
    <button class="form-element" type="submit">Register</button>
</gameface-form-control>

As you can see some attributes are used to validate the user name. The url and email will be validated by default. We can add our custom validators using the methods exposed in the gameface-form-control component. Note: Custom validation should be added after the form control bundle is added to the page.

// Custom validators should be set after the components library is added!

const form = document.getElementById('custom-validation-form');

let serverError = false, serverNotReachable = false;
//Will set custom validators for the form element with name attribute that has value - "username"
form.setCustomValidators('username', {
    //There is no required attribute to the form element so we can add validation about it here
    valueMissing: {
        method: (element) => !element.value,
        errorMessage: () => 'The username is required! '
    },
    //We can change the default message on the 'tooShort' preset validator
    tooShort: { errorMessage: (element) => `The username should have more than ${element.getAttribute('minlength')} symbols typed! `},
    //Async validator that checks if the user is already added to the database by making a request to the server
    usernameExists: {
        method: async (element) => {
            if (!element.value) return false;

            serverError = false;
            serverNotReachable = false;
            return new Promise((resolve) => {
                const xhr = new XMLHttpRequest();
                xhr.open('GET', `http://localhost:3000/user-exists?username=${element.value}`);
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                xhr.onload = (event) => resolve(event.target.response === 'true');
                xhr.onerror = () => {
                    serverError = true;
                    return resolve(true)
                }
                xhr.timeout = 1000;
                xhr.ontimeout = () => {
                    serverNotReachable = true;
                    return resolve(true)
                }
                xhr.send();
            })
        },
        errorMessage: (element) => {
            if (serverNotReachable) return 'Unable to reach the server! ';
            if (serverError) return 'Unable to reach the server due an error! ';

            return `"${element.value}" already used! Please use another one! `;
        }
    }
});
//By default the error will be visible in a tooltip displayed next to the form element
//We can change that behavior for the user name by selecting another element for this purpose
form.setCustomDisplayErrorElement('username', '#username-error');

//We can set a custom validation of the form element with a custom method and a message
form.setCustomValidators('url', {
    notStartingWithHttpProtocol: {
        method: (element) => !element.value.startsWith('http://') && !element.value.startsWith('https://'),
        errorMessage: () => 'The url should start with "http://" or "https://"!'
    }
});

form.setCustomValidators('email', {
    //We can remove the preset error message if the preset validator for email fails
    //That will also remove the tooltip because no error messages should be visible even if the check fails
    badEmail: {
        errorMessage: () => ''
    }
});

Accessing the XMLHttpRequest

An XMLHttpRequest is created when a form is submitted. It is helpful to access this XHR in case you need to check the status of the request, the response, or if you want to do something on success/error. You can access this request through the properties of the form control:

<gameface-form-control id="my-form" action="http://localhost:3000/options" method="POST">
    <input type="text" name="user" value="name" />
    <button type="submit">Submit</button>
</gameface-form-control>

const form = document.getElementById('my-form');
const xhr = form.xhr;

xhr.addEventListener('progress', () => console.log('onProgress'));
xhr.addEventListener('load', () => console.log('load'));
xhr.addEventListener('error', () => console.log('error'));
xhr.addEventListener('abort', () => console.log('abort'));