Form - globules-io/OGX.JS GitHub Wiki

Form is a helper object to deal with fields and forms specially on mobile. It can be used as a static class to control an HTML form (static form), or to generate an instance of FormInstance, that will be controlled by OGX.Form.

OGX.Form doesn't need to be instantiated, it is built as a static class.

Dynamic Forms 1.20.0+

You can generate forms using predefined types of controls for each type of value. Here's the default configuration per type. Note that the OML tag for this object will be FormInstance

 {
     templates:{
          row: '<span class="row"><span class="label">{{$prop}}</span>{{$html}}</span>',
          form: '<form>{{$rows}}</form>'
     },
     types: {
         boolean : {html: '<span class="{{$name}}"></span>', oml:'{"default .{{$name}}:Switch":{"name" : "{{$prop}}", "val":{{$val}} }}'},
         string : {html: '<input type="text" name="{{$prop}}" value="{{$val}}" {{$required}} {{$pattern}} {{$readonly}}>'},
         number : {html: '<input type="number" name="{{$prop}}" value="{{$val}} {{$required}} {{$pattern}} {{$readonly}}">'},
         array : {html: '<span class="{{$name}}"></span>', oml:'{"default .{{$name}}:Tags":{"name" : "{{$prop}}", "current_tags":{{$val}} }}'}
     }
 }

You can overwrite each type as you like. In this config, booleans are handled via a Switch, strings and number via HTML input, and arrays via Tags. To overwrite, simply edit the object

 OGX.Form.defaults

To create a dynamic form (from an Object) from within a Uxi

 let obj = {name:'something', weight:55, sizes:['small', 'medium', 'large']};
 let form_instance = OGX.Form.fromObject(obj, this, '.my_selector');
 form_instance.onChange = function(obj){ ... };     

You can also pass a config object for the entire form, when creating the instance

 let form_instance = OGX.Form.fromObject(obj, this, '.my_selector', {validate:true, fields:{
      name:{
          readonly: false,
          required : true,
          pattern: '[0-9]+',
          fullpath: false,          
          ... all other properties from default config
      }          
 });

For more information about the config object, scroll down to Config. Note that readonly, pattern, required, fullpath are only available when creating a dynamic form.

fullpath when set to true will display the entire path to the propery, such as

 {server:{version:'1.0.0'}}

Will output as label server.version

Static Forms

You can also bind a form to Form which will prevent the default submit behavior.

 OGX.Form.bindForm(_CONFIG_);
 OGX.Form.unbindForm(_SELECTOR_); //If `_SELECTOR_` is not passed, the method acts as a shortcut to `unbindAll('form')`
 OGX.Form.unbindAll('form');

Note that omitting to pass a selector to unbindForm will unbind all forms

Config

  {
      el:_SELECTOR_, //Mandatory, the selector
      allowed:false, //Optional, see fields
      forbidden:false, //Optional, see fields
      change_cb:_FUNCTION_, //Optional, callback fired upon change
      submit_cb:_FUNCTION_ //Optional, callback fired upon submit,
      validate:_BOOL_, //Optional, validates the form on submit,
      diff:_BOOL_, //Optional, if set to true, only triggers a change when a value of the form changes,
      params: * , //Optional parameters to pass,
      elem_types:_ARRAY_, //Optional, the list of element types to consider a child of the form, defaults to ['input', 'textarea'],
      wait:_INT_, //Optional, overwrite the field wait time globally
  }

In this case, config is an general configuration object that overrides fields settings unless specified, such as

 OGX.Form.bindForm({
      el:'#myForm', 
      forbidden:/<>/, 
      wait:500,
      change_cb:onChange,
      submit_cb:onSubmit,
      fields:{
           body:{
                wait:50
           }
      }         
 });

You can also set any of the flags available at form level or at field level.

 OGX.Form.bindForm({
      el:'#myForm', 
      forbidden:/<>/, 
      wait:500,
      change_cb:onChange,
      submit_cb:onSubmit,
      fields:{
           body:{
                wait:50
                forbidden:/<>[0-9]/,
                multiline:true
           }
      }         
 });

This configuration will listen to all fields of the form #myForm, forbid entry of <> chars on all fields, wait 500ms to consider that a field has changed after user last input for all fields BUT the field that has 'body' as name, which only waits 50 ms after last user input to trigger a change.

OGX.Form will return a JSON object composed by the names of the fields as properties and their value such as

 <form id="myForm">
      <input type="text" name="first_name" placeholder="First Name" val="John">
      <input type="text" name="last_name" placeholder="Last Name" val="Green">
      <input type="submit" value="send">
 </form>

Will return

 {
      obj:{first_name:"John", last_name:"Green"}, 
      el:_HTML_ELEMENT_
 }

by either going the callback route in the form config

 function onSubmit(__data, __extra_param){
     console.log('user wants to send out', __data.obj);
 }

or by listening for a change

 OGX.Form.bindForm('#myForm');

 $('#myForm').on('change', function(__e, __data){
       console.log('user wants to send out', __data.obj);
 });

Do not forget to unbind your form when/if you destroy your view

OGX.Form.unbindForm('#myForm');

Fields

The callback or event is going to also be fired when a field of the form changes (via bindField)

Get & Update 1.8.4+

You can also update a bind configuration at runtime. To look up a bind, use

 let bind = OGX.Form.getBind(SEARCH_STRING);

Note that SEARCH_STRING searches over selectors.

To update a bind configuration

OGX.Form.updateBind(SEARCH_STRING, OBJECT);

A practical example

OGX.Form.updateBind('zip', {mask:'%%% %%%'});

Populate

You can also populate a form given an object. Note that all input elements of the form must have a name attribute declared that matches a property of the given object. Also note that select isn't supported mainly because it is replaced by Roulette

 OGX.Form.populate('#myForm', obj);   

Note that populate also supports deep paths, such as

 <input type="text" name="created.date">

will be populated from

 {created:{date:'1980-01-01'}, ...}

Populate also supports an optional map object to be used to transform data before populating. Each value of the map object must be a function. Here we add decimals to a total. 1.15.0+

 OGX.Form.populate('#myForm', {total:100}, {total:OGX.Data.addDec});   

Validate

You can also validate a form if the native HTML5 validation is not available (like on iOS Webview at the time this documentation is being written). Note that it still requires the pattern and required attributes.

  let validation = OGX.Form.validate(_SELECTOR_);

Will return an object composed by names of failing fields as properties, such as

  {login:false, password:false, ....}

If you wish to have an automatic validation upon submit, you can set the flag validate to true in the form config. In this case, a property is added to the object passed to your submit call back, such as

  {
      obj:{first_name:"John", last_name:"Green"}, 
      el:_HTML_ELEMENT_,
      valid:true|false,
      error:_OBJECT_ //only if !valid
  }

Change 1.26.0+

You can force a bound form to trigger the cb_change callback by doing

 OGX.Form.change('#my_form');

Fields

Binding a text field (and variants such as tel, email, password...) is generally used if you want to save the information that was entered by the end user, without requiring to tap/click on a button or any other step to save the data.

 OGX.Form.bindField(_CONFIG_);
 OGX.Form.unbindField(_SELECTOR_); //if `_SELECTOR_` is not passed, the method acts as a shortcut to `unbindAll('field')`
 OGX.Form.unbindAll('field');

Config

The expected CONFIG object is as follow

 {
      el:false, //Mandatory, the selector
      allowed:Regex, //Optional, allowed chars, defaults to /[0-9a-zA-Z‘’'"à-úÀ-Ú\\-\\!\\.\\?\\#\\@\\$\\:\\(\\)\\/_,;%' ]/
      forbidden:false, //Optional, regex, forbidden chars 
      mask:false, //Optional, see masking
      mask_char:_STRING_, //Optional, the char to use for the masking, see masking
      paste:true, //Optional, allow paste
      autocomplete:true, //Optional, allow autocomplete
      multiline:false, //Optional, multiline
      submit: false, //Optinal, if the field triggers a submit when pressing enter/return
      validate:false, //Optional, return a valid flag based on pattern attribute        
      input_cb:false, //Optional, the callback to call upon input change 
      change_cb:false, //Optional, the callback to call upon field value change 
      wait:1000, //Optional, the delay before a change is considered a change      
      diff:true, //Optional, only triggers change if the field value after wait differs  
      max:2500, //Optional, the max length for the value
      type:'string|number|int|bool|json', //Optional, forces a type
      params:null, //Optional extra parameters
 }

Binding a field listens to its changes and broadcasts (or calls a callback) the change after a certain time. It also broadcasts (or calls a callback) if the key enter is pressed.

In the following example, we listen to a field that will call a function once the value of the field is considered final either by waiting 1500ms after the last input or by pressing return

 function onFieldChange(__obj, __extra_param){
      //passes
      {
           obj:{property:value}, 
           property:value
           value:value,
           el:_HTML_ELEMENT_
      } 
      //such as, for a field named "first_name"
      {
           obj:{first_name:'Jack'}, 
           property:'first_name',
           value:'Jack',
           el:_HTML_ELEMENT_
      }          
 }

 OGX.Form.bindField({
      el:'input[name="first_name"]',           
      change_cb:onFieldChange, 
      wait:1500
 });

If you don't want to use callbacks, you can listen to your field as usual and the "change" event will be replaced by Form "change" event and will fire after 1500ms or by pressing the return key.

 $('input[name="first_name"]').on('change', function(__e){
      console.log($(this).val()); //The value of the field
 });

The input_cb is fired when the user presses a key (same as 'input' event) if you wish to use this shortcut.

Restricting Fields

There are two ways to restrict inputs on fields. You either pass the allowed and/or forbidden flags in the config of a bind while binding a field, or you can use the restrictField method. It is recommended to always use the bindField method but if you only want to restrict and not listen to this field, you can use the (smaller) restrictField method.

You can also restrict the input on any element (input fields and contenteditable elements), if you wish, for instance, to allow only certain characters to be typed.

 OGX.Form.restrictField(_CONFIG_);
 OGX.Form.unrestrictField(_SELECTOR_);

So to restrict to letters only with a max of 100 characters, pass

 let config = {el:'input[name="first_name"]', allowed:/[a-zA-Z]/, max:100}; 

If you'd rather work with forbidden chars, use the forbidden parameter instead and omit the allowed parameter

 let config = {el:'input[name="first_name"]', forbidden:/[<>]/, max:100}; 

Note that if allowed if set, forbidden will be ignored.

You can also use the pattern attribute for input fields, in this case, the regular expression from this attribute super classes the options and the forbidden flag will be ignored.

Also you can set the parameter autocomplete to true if you want to allow auto complete and paste if you want to allow paste on the field.

Masking

You also mask a field by setting a mask such as (in case of a North American phone number)

 {..., mask:'%%%-%%%-%%%%', mask_char:'%', ...}

Note that the default mask_char is already set to '%' but you can change it to whatever you want.

Enable

To enable all listeners

 OGX.Form.enable();

To enable all fields of a form

OGX.Form.enableForm('#myform');

To enable all fields of all bound forms

OGX.Form.enableForm();

Disable

To disable all listeners

 OGX.Form.disable();

To disable the fields of a form

OGX.Form.disableForm('#myform');

To disable all fields of all bound forms

OGX.Form.disableForm();

Additional Methods

Convert form data to object by using the name property of fields

 let obj = OGX.Form.toObj('#myForm');

To skip the disabled/readonly elements

 let obj = OGX.Form.toObj('#myForm', true);

Unbind everything

 OGX.Form.unbindAll(_TYPE_); //String

The expected _TYPE_ is either all, form or field

⚠️ **GitHub.com Fallback** ⚠️