ng-formality v0.1.3
Introduction
Formality is a form builder built with Angular. It uses Angular's Reactive Forms and ng-bootstrap (Bootstrap 5). Formality supports a variety of control Types.
Goals
- Improve scalability.
- Ease front-end developer workload if the form is dynamic, and its structure is defined in the backend. Unless a distinctive styling for a control is needed, there should be no additional effort needed to CRUD a control in the front-end.
- Keep website forms' layout and styling consistent.
- Reuse the logic of rendering forms.
- Keep website modular by having forms rendering and forms' data seperate.
Additionaly, FormalityUtils class provides additional functions:
- Generate styling template for your unique form structure
- Object structure validity checking
Note:
FormalityUtilscurrently generates SCSS styling template only.
Types
- Text
- Password
- Email
- Number
- Search
- Mobile-- telinput type.
- Url
- Textarea
- Article- a rich WYSIWYG text editor that uses ngx-quill package.
- Checkbox- can be intermediate.
- Switch- same as- Checkboxbut displayed as switch. Cannot be intermediate.
- Radio
- RadioGroup
- Range
- Date
- Select- a drop down with several values. Can be single, or multi. It uses ng-select package.
- Country- a drop down with country name and their flags.
- File
- Image
- Form- used in order for controls to be grouped in the DOM tree, and to be grouped in Angular's- FormGroup.
- Group- used in order for controls to be grouped in the DOM tree.
Data structure
You may define the object as a JSON, typescript object, or receive it from the backend. The object is constrained by abstract FormalityControl type, which can be nested.
Additional constraints:
- A Groupmust havecontrolsproperty and must not havevalueproperty.
- A RadioGroupmust have bothvalueandcontrolsproperties.
- All other controls, including FormGroup, must have valueproperty and shouldn't havecontrolsproperty.
- No identical parent and child name combinations within a form or within all active Formalityforms.
Any FormalityControl value may be in form of a control or array of controls, including the base object, allowing you to wrap your form elements inside a single group or keep them seperate in the DOM tree.
Form controls' classes
Formality creates a DOM tree with css selectors in a predictable manner:
- Form: {control.name}-form formclass.- Controls: {control.name}-controls controlsclass.- Control: {control.name}-controlclass (also{control.name}{parent.name}id).
- Label: {control.name}-labelclass.
 
- Control: 
 
- Controls: 
You can use that to make unified style for your forms by selecting subform and controls, and/or make distinctive styles by selecting controls by their name.
Formality adds is-valid, is-invalid classes according to control's validity.
Usage
1. Define your form.
form1.json:
{
  "label": "Formality - optimise productivity!",
  "name": "baseGroup",
  "type": "group",
  "controls": [
    {
      "name": "yourAge",
      "label": "Whats your age",
      "value": "10",
      "type": "text",
      "validators": {
        "required": true,
        "minlength": 2
      }
    },
    {
      "name": "simpleSwitch",
      "label": "Do you like switches?",
      "value": false,
      "type": "switch",
      "validators": {
        "requiredTrue": true
      }
    }
  ]
}2. Pass the object to FormalityComponent.
Give form an
idif you're going to style multiple forms differently.
<formality class="col-lg-6 col-12" id="test1" [formData]="form1"> </formality>3. Use FormalityUtils class to get .scss styling template.
console.log(FormalityUtils.generateScssSnippet(form1, SnippetType.Specific));Copy and paste the code to styles.scss (or a file, included in styles.scss for better seperation). If you want to make sure styles for common selectors like subform and controls only impact this form - wrap it inside your id. In this case - it is test1. Format the snippet. Result:
#test1 {
  .baseGroupsubform {
    .baseGroupcontrols {
      .yourAge {
      }
      .simpleSwitch {
      }
    }
  }
}Add styling as you see fit.
4. Subscribe to form submittions.
  @ViewChild(FormalityComponent) form: FormalityComponent;
  form.onSubmitted.subscribe((value) => console.log(value));5. Introduce restrictions checking (Optional)
FormalityUtils.checkDataValidity(form1);Bootstrap integration improvement
A inconsistency within bootstrap is that for some control types bootstrap has the following layout:
label control
but for other, such as a checkbox layout is reversed:
control label
In ng-formality we render all controls using the latter, with the help of a flexbox and an order attribute when needed. That allows the code of FormControlComponent to be simpler. However, styling of valid/invalid control is missing for some control labels.
Thus, you should add the following code in _forms.scss of ng-bootstrap file if you want all invalid control labels to be highlighted.
.form-control {
  @include form-validation-state-selector($state) {
    ~ .form-label {
      color: $color;
    }
  }
}FAQ
- This library is tied to Bootstrap. Is it not going to make all my websites look the same?No. There are many bootstrap theme collection websites available online. Make sure it is Bootstrap 5 and replace the style sheets to have completely different look with minimal effort. 
Future improvements
- Support for FormArray.
- Support prefilling image field.
- Add option to keep image file name.
- Support mobile number input by displaying country's flag, country's mobile code dropdown next to an input field.
- Seperate date,timeanddatettimetypes (or add options to existing control).
- Extend Selecttypes to be capable of holding a value different than its name.
- Use moment to format date. Add ability to pass format.
- Add range and select validity check in FormalityUtils.
- Add ability to have a select with labels and values different from labels, just like with RadioGrouptype.
- Extend FormalityUtilsto generate SASS template.
- Option for an image to be displayed when uploaded.
- Solve dependancy on ngx-translate.
- Create a online tool for generating style sheet templates.
- Perhaps remove Radiotype because this type is certain by being in aRadioGrouptype parent.
- Perhaps implement lazy loading for CountrySelecttype, as it will be more rarely used and requires loading countries flags.
- Perhaps bootstrap control classes by Cascading Style Sheet's @extendkeyword, instead of Angular's[class]binding would give more flexibility.
- Perhaps add ability to pass FormalityComponentwhen generating stylesheet, in order to include its ID.
- Support partial editted form values for ability to send PATCHrequests.
- For more optimised POSTrequests with binary files, implement value conversion to FormData (multipart/form-data) type.
PRs are welcome!