"positive"
14 | };
15 | };
--------------------------------------------------------------------------------
/templates/default/select-field/_multi-select.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/templates/default/text-field/_textarea.html:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/templates/bootstrap/text-field/_textarea.html:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/styles/default/field-label.styl:
--------------------------------------------------------------------------------
1 | @require '_variables';
2 |
3 | field-label {
4 | display: inline-block;
5 | }
6 |
7 | .field-label {
8 | position: relative;
9 | cursor: inherit;
10 | font-weight: bold;
11 | user-select: none;
12 |
13 | &:hover {
14 | .form-for-tooltip {
15 | .form-for-tooltip-popover {
16 | display: inline-block;
17 | }
18 | }
19 | }
20 | }
21 |
22 | .field-label-required-label {
23 | color: $color-text-1;
24 | font-style: italic;
25 | font-size: .8em;
26 | }
27 |
--------------------------------------------------------------------------------
/tests/unit/services/parse.js:
--------------------------------------------------------------------------------
1 | describe('$parse', function() {
2 | 'use strict';
3 |
4 | beforeEach(module('formFor'));
5 |
6 | var $parse;
7 |
8 | beforeEach(inject(function ($injector) {
9 | $parse = $injector.get('$parse');
10 | }));
11 |
12 | describe('StringUtil', function() {
13 | it('should gracefully handle null and empty strings', function() {
14 | var data = {};
15 |
16 | $parse('names[0]').assign(data, 'value');
17 |
18 | expect(data.names[0]).toEqual('value');
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/templates/default/text-field/_input.html:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/source/utils/form-for-guid.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * UID generator for formFor input fields.
5 | * @see http://stackoverflow.com/questions/6248666/how-to-generate-short-uid-like-ax4j9z-in-js
6 | *
7 | * Intended for use only by formFor directive; this class is not exposed to the $injector.
8 | */
9 | export class FormForGUID {
10 |
11 | /**
12 | * Create a new GUID.
13 | */
14 | public static create():string {
15 | return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4);
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/templates/bootstrap/text-field/_input.html:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-boolean.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Associates a boolean validation rule with a custom failure message.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleBoolean {
9 |
10 | /**
11 | * This rule is active.
12 | * If the condition it applies to is not met, the field should be considered invalid.
13 | */
14 | rule:boolean;
15 |
16 | /**
17 | * Custom error message to be shown for failed validations.
18 | */
19 | message:string;
20 | };
21 | };
--------------------------------------------------------------------------------
/source/interfaces/bindable-collection-wrapper.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * A bind-friendly wrapper object describing the state of the collection.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface BindableCollectionWrapper {
9 |
10 | /**
11 | * Header should display the string contained in this field (if one exists); this means the collection is invalid.
12 | */
13 | error?:string;
14 |
15 | /**
16 | * Header should display a 'required' indicator if this value is true.
17 | */
18 | required:boolean;
19 | };
20 | };
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-field-type.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Associates a field-type validation rule with a custom failure message.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleFieldType {
9 |
10 | /**
11 | * The required field type.
12 | * If the condition it applies to is not met, the field should be considered invalid.
13 | */
14 | rule:ValidationFieldType;
15 |
16 | /**
17 | * Custom error message to be shown for failed validations.
18 | */
19 | message:string;
20 | };
21 | };
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-number.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Associates a numeric validation rule with a custom failure message.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleNumber {
9 |
10 | /**
11 | * Describes the numeric constraint to be applied to the associated field.
12 | * If the condition is not met, the field should be considered invalid.
13 | */
14 | rule:number;
15 |
16 | /**
17 | * Custom error message to be shown for failed validations.
18 | */
19 | message:string;
20 | };
21 | };
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-custom.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Associates a custom validation rule with a custom failure message.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleCustom {
9 |
10 | /**
11 | * Custom validation function.
12 | * If this function returns a rejected promise or a falsy value, the field should be considered invalid.
13 | */
14 | rule:CustomValidationFunction;
15 |
16 | /**
17 | * Custom error message to be shown for failed validations.
18 | */
19 | message:string;
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-regexp.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Associates a RegExp validation rule with a custom failure message.
5 | *
6 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleRegExp {
9 |
10 | /**
11 | * Describes the regular expression condition to be applied to the associated field.
12 | * If the condition is not met, the field should be considered invalid.
13 | */
14 | rule:RegExp;
15 |
16 | /**
17 | * Custom error message to be shown for failed validations.
18 | */
19 | message:string;
20 | };
21 | };
--------------------------------------------------------------------------------
/templates/bootstrap/field-label.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/templates/default/field-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 | ?
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-form-for",
3 | "version": "4.1.10",
4 | "main": [
5 | "./dist/form-for.css",
6 | "./dist/form-for.js"
7 | ],
8 | "homepage": "https://github.com/bvaughn/angular-form-for",
9 | "authors": [
10 | "Brian Vaughn "
11 | ],
12 | "description": "Set of Angular directives to simplify creating and validating HTML forms.",
13 | "keywords": [
14 | "angular",
15 | "form",
16 | "forms",
17 | "crud",
18 | "validation"
19 | ],
20 | "license": "MIT",
21 | "ignore": [
22 | "**/.*",
23 | "node_modules",
24 | "bower_components",
25 | "test",
26 | "tests"
27 | ],
28 | "dependencies": {},
29 | "devDependencies": {}
30 | }
31 |
--------------------------------------------------------------------------------
/source/interfaces/field-datum.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Wrapper object containing using information about a formFor field.
5 | *
6 | * Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface FieldDatum {
9 |
10 | /**
11 | * Shared between formFor and field directives.
12 | */
13 | bindableWrapper:BindableFieldWrapper;
14 |
15 | /**
16 | * Uniquely identifies a form field.
17 | */
18 | fieldName:string;
19 |
20 | /**
21 | * Helper utility class used by formFor and its directives.
22 | */
23 | formForStateHelper:FormForStateHelper;
24 |
25 | /**
26 | * Callbacks for removing $scope.$watch watchers.
27 | */
28 | unwatchers:Array;
29 | };
30 | };
--------------------------------------------------------------------------------
/source/interfaces/validation/validation-rule-collection.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Describes rules for validating a form-field that contains a collection.
5 | *
6 | * Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export interface ValidationRuleCollection {
9 |
10 | /**
11 | * Rules for validating properties of objects within the current collection.
12 | * See {@link ValidationRules}.
13 | */
14 | fields?:ValidationRuleSet;
15 |
16 | /**
17 | * The collection must contain no more than this many items.
18 | */
19 | max?:number|ValidationRuleNumber;
20 |
21 | /**
22 | * The collection must contain at least this many items.
23 | */
24 | min?:number|ValidationRuleNumber;
25 | };
26 | };
--------------------------------------------------------------------------------
/source/interfaces/custom-validation-function.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Describes the signature(s) for a custom field validation function.
5 | *
6 | *
This function is passed the following parameters:
7 | *
8 | * value: The value of the field, as entered into the form
9 | * formData: The entire form data object
10 | *
11 | *
12 | * This function should return either a truthy/falsy value or a Promise to be resolved/rejected.
13 | * If a Promise is returned, it can be rejected with a custom validation error message.
14 | *
15 | *
Note that this interface exists for type-checking only; nothing actually implements this interface.
16 | */
17 | export interface CustomValidationFunction {
18 | (value:any, formData:any, fieldName:any): boolean|ng.IPromise;
19 | };
20 | };
--------------------------------------------------------------------------------
/source/enums/validation-failure-type.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Identifies a validation failure type.
5 | */
6 | export enum ValidationFailureType {
7 | COLLECTION_MAX_SIZE = "COLLECTION_MAX_SIZE",
8 | COLLECTION_MIN_SIZE = "COLLECTION_MIN_SIZE",
9 | CUSTOM = "CUSTOM",
10 | INCREMENT = "INCREMENT",
11 | MAXIMUM = "MAXIMUM",
12 | MAX_LENGTH = "MAX_LENGTH",
13 | MINIMUM = "MINIMUM",
14 | MIN_LENGTH = "MIN_LENGTH",
15 | PATTERN = "PATTERN",
16 | REQUIRED = "REQUIRED_FIELD",
17 | TYPE_EMAIL = "TYPE_EMAIL",
18 | TYPE_INTEGER = "TYPE_INTEGER",
19 | TYPE_NEGATIVE = "TYPE_NEGATIVE",
20 | TYPE_NON_NEGATIVE = "TYPE_NON_NEGATIVE",
21 | TYPE_NUMERIC = "TYPE_NUMERIC",
22 | TYPE_POSITIVE = "TYPE_POSITIVE"
23 | };
24 | };
--------------------------------------------------------------------------------
/templates/default/checkbox-field.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/templates/material/radio-field.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/styles/default/field-error.styl:
--------------------------------------------------------------------------------
1 | @require '_variables';
2 |
3 | error-field-background-color = rgba(red, .95);
4 |
5 | .field-error {
6 | position: absolute;
7 | top: 100%;
8 | border-radius: 4px;
9 | background-color: red;
10 | background-color: error-field-background-color;
11 | color: white;
12 | padding: 7px 15px;
13 | z-index: 1000;
14 | margin: 0;
15 | pointer-events: none;
16 |
17 | &::before {
18 | content: '';
19 | border: 7px solid transparent;
20 | position: absolute;
21 | bottom: 100%;
22 | border-bottom-color: red;
23 | border-bottom-color: error-field-background-color;
24 | }
25 |
26 | &:not(.left-aligned) {
27 | right: 3px;
28 |
29 | &::before {
30 | right: 10px;
31 | }
32 | }
33 |
34 | &.left-aligned {
35 | left: 0;
36 |
37 | &::before {
38 | left: 4px;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/source/directives/aria-manager.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Helper directive for input elements.
5 | * Observes the $scope :model attribute and updates aria-* elements accordingly.
6 | */
7 | export class AriaManager implements ng.IDirective {
8 |
9 | restrict:string = 'A';
10 |
11 | /* @ngInject */
12 | link($scope:ng.IScope, $element:ng.IAugmentedJQuery, $attributes:ng.IAttributes):void {
13 | $scope.$watch('model.uid', function(uid) {
14 | $attributes.$set('ariaDescribedby', uid + '-error');
15 | $attributes.$set('ariaLabelledby', uid + '-label');
16 | });
17 |
18 | $scope.$watch('model.error', function(error) {
19 | $attributes.$set('ariaInvalid', !!error);
20 | });
21 | }
22 | }
23 |
24 | angular.module('formFor').directive('ariaManager', () => {
25 | return new AriaManager();
26 | });
27 | }
--------------------------------------------------------------------------------
/templates/bootstrap/checkbox-field.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | var config = {
2 | allScriptsTimeout: 11000,
3 |
4 | capabilities: {
5 | browserName: 'chrome',
6 | shardTestFiles: true,
7 | maxInstances: 2
8 | },
9 |
10 | specs: [
11 | 'tests/integration/**/*.js'
12 | ],
13 |
14 | seleniumAddress: 'http://localhost:4444/wd/hub',
15 | baseUrl: 'http://localhost:8000/examples/',
16 |
17 | framework: 'jasmine2',
18 | rootElement: 'body',
19 |
20 | jasmineNodeOpts: {
21 | showColors: true, // Use colors in the command line report.
22 | defaultTimeoutInterval: 30000
23 | }
24 | };
25 |
26 | if (process.env.TRAVIS_BUILD_NUMBER) {
27 | config.sauceUser = process.env.SAUCE_USERNAME;
28 | config.sauceKey = process.env.SAUCE_ACCESS_KEY;
29 | config.capabilities['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER;
30 | config.capabilities.build = process.env.TRAVIS_BUILD_NUMBER;
31 | }
32 |
33 | exports.config = config;
--------------------------------------------------------------------------------
/styles/default/_variables.styl:
--------------------------------------------------------------------------------
1 | $color-fill-1 = #f9f9f9
2 | $color-fill-2 = #EFEFEF
3 | $color-fill-3 = #CCC
4 | $color-fill-4 = #AAA
5 | $color-fill-5 = #999
6 | $color-fill-6 = #666
7 |
8 | $color-text-1 = #848b88
9 | $color-text-2 = #3d3f3e
10 | $color-text-3 = #252726
11 |
12 | light-blue = #ebf6ff
13 | medium-blue = #66afe9
14 |
15 | blue = #0075ba
16 | gray = $color-fill-4
17 | green = #8eb32b
18 | orange = #ea9707
19 | purple = #813793
20 | red = #e35256
21 | teal = #00a99d
22 | yellow = #ead207
23 |
24 | $border-color = $color-fill-4
25 | $border = 1px solid $border-color
26 | $border-radius = 6px
27 | $border-color-focused = medium-blue
28 | $border-color-error = red
29 | $box-shadow-focused = 0 0 4px medium-blue;
30 | $box-shadow-error-focused = 0 0 4px red;
31 |
32 | $padding-small = 5px
33 |
34 | $opacity-disabled = .5
35 |
36 | $transition = all 100ms linear
37 |
38 | $box-shadow = inset 0 1px 1px rgba(0,0,0,.075)
39 |
--------------------------------------------------------------------------------
/templates/default/radio-field.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/styles/default/submit-button.styl:
--------------------------------------------------------------------------------
1 | @import 'nib';
2 | @require '_variables';
3 |
4 | submit-field {
5 | display: block;
6 | }
7 |
8 | .submit-button {
9 | user-select: none;
10 |
11 | transition: $transition;
12 |
13 | border-radius: $border-radius;
14 | border-style: none;
15 | background-color: blue;
16 | color: white;
17 | cursor: pointer;
18 | display: inline-block;
19 | font-size: inherit;
20 | font-weight: 400;
21 | line-height: 35px;
22 | outline: 0;
23 | padding: 0 25px;
24 | white-space: nowrap;
25 |
26 | &:not(.disabled):not(:disabled) {
27 | &:hover, &:active, &:focus {
28 | background-color: lighten(blue, 5%);
29 | color: white;
30 | }
31 | }
32 |
33 | &:active {
34 | transition: none;
35 |
36 | box-shadow: inset 0 4px 2px rgba(0,0,0, 0.1);
37 | }
38 |
39 | &.disabled,
40 | &:disabled {
41 | opacity: .5;
42 | cursor: default;
43 | box-shadow: none;
44 | }
45 | }
46 |
47 | .submit-button-icon {
48 | margin-right: 5px;
49 | }
50 |
--------------------------------------------------------------------------------
/source/utils/string-util.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Utility for working with strings.
5 | *
6 | * Intended for use only by formFor directive; this class is not exposed to the $injector.
7 | */
8 | export class StringUtil {
9 |
10 | /**
11 | * Converts text in common variable formats to humanized form.
12 | *
13 | * @param text Name of variable to be humanized (ex. myVariable, my_variable)
14 | * @returns Humanized string (ex. 'My Variable')
15 | */
16 | public static humanize(text:string):string {
17 | if (!text) {
18 | return '';
19 | }
20 |
21 | text = text.replace(/[A-Z]/g, function (match) {
22 | return ' ' + match;
23 | });
24 |
25 | text = text.replace(/_([a-z])/g, function (match, $1) {
26 | return ' ' + $1.toUpperCase();
27 | });
28 |
29 | text = text.replace(/\s+/g, ' ');
30 | text = text.trim();
31 | text = text.charAt(0).toUpperCase() + text.slice(1);
32 |
33 | return text;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/templates/default/select-field.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
20 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/templates/bootstrap/radio-field.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/templates/default/text-field.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(config) {
4 | config.set({
5 | autoWatch: true,
6 | basePath: '',
7 | frameworks: ['jasmine'],
8 | preprocessors: {
9 | 'templates/**/*.html': 'ng-html2js'
10 | },
11 | // See https://github.com/karma-runner/karma-ng-html2js-preprocessor
12 | ngHtml2JsPreprocessor: {
13 | },
14 | files: [
15 | 'node_modules/jquery/dist/jquery.js',
16 | 'node_modules/angular/angular.js',
17 | 'node_modules/angular-mocks/angular-mocks.js',
18 | 'node_modules/jasmine-object-matchers/dist/jasmine-object-matchers.js',
19 | 'node_modules/jasmine-promise-matchers/dist/jasmine-promise-matchers.js',
20 | 'dist/form-for.js',
21 | 'tests/unit/**/*.js',
22 | 'templates/**/*.html'
23 | ],
24 | exclude: [],
25 | port: 9999,
26 | browsers: [
27 | 'PhantomJS'
28 | ],
29 | plugins: [
30 | 'karma-phantomjs-launcher',
31 | 'karma-jasmine',
32 | 'karma-ng-html2js-preprocessor'
33 | ],
34 | singleRun: false,
35 | colors: true,
36 | logLevel: config.LOG_INFO
37 | });
38 | };
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Brian Vaughn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/templates/bootstrap/select-field.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
12 |
13 |
14 |
16 |
17 |
18 |
21 |
22 |
25 |
26 |
29 |
30 |
--------------------------------------------------------------------------------
/templates/material/select-field.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
15 | {{option[labelAttribute]}}
16 |
17 |
18 |
19 |
24 |
25 |
27 | {{option[labelAttribute]}}
28 |
29 |
30 |
31 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/templates/material/type-ahead-field.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
21 |
22 |
23 | {{option[labelAttribute]}}
24 |
25 |
26 |
27 |
28 | No matches found for "{{scopeBuster.filter}}".
29 |
30 |
31 |
32 |
34 |
35 |
--------------------------------------------------------------------------------
/templates/material/text-field.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
18 |
19 |
31 |
32 |
35 |
--------------------------------------------------------------------------------
/styles/default/tooltip.styl:
--------------------------------------------------------------------------------
1 | @require '_variables';
2 |
3 | .form-for-tooltip {
4 | display: inline-flex;
5 | align-items: center;
6 | height: 15px;
7 | width: 15px;
8 | }
9 |
10 | .form-for-tooltip-icon {
11 | display: inline-block;
12 | width: 15px;
13 | height: 15px;
14 | flex: 0 0 15px;
15 | border-radius: 15px;
16 | line-height: 15px;
17 | background-color: $color-text-1;
18 | color: white;
19 | text-align: center;
20 | font-weight: 600;
21 | font-size: 12px;
22 | cursor: default;
23 |
24 | &:hover {
25 | background-color: $color-text-2;
26 | }
27 | }
28 |
29 | .form-for-tooltip-popover {
30 | pointer-events: none;
31 | display: none;
32 | position: relative;
33 | z-index: 2;
34 | flex: 0 0 350px;
35 | width: 350px;
36 | border-radius: $border-radius;
37 | padding: 15px;
38 | margin-left: 15px;
39 | background-color: light-blue;
40 | color: $color-text-3;
41 | border-bottom: 1px solid rgba(0,0,0,.15);
42 | font-weight: 400;
43 |
44 | &:before {
45 | position: absolute;
46 | right: 100%;
47 | top: 50%;
48 | margin-top: -10px;
49 | content: '';
50 | border: 10px solid transparent;
51 | border-right-color: light-blue;
52 | color: $color-text-3;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/templates/bootstrap/text-field.html:
--------------------------------------------------------------------------------
1 |
33 |
--------------------------------------------------------------------------------
/tests/unit/services/string-util.js:
--------------------------------------------------------------------------------
1 | describe('StringUtil', function() {
2 | 'use strict';
3 |
4 | beforeEach(module('formFor'));
5 |
6 | describe('StringUtil', function() {
7 | it('should gracefully handle null and empty strings', function() {
8 | expect(formFor.StringUtil.humanize(null)).toEqual('');
9 | expect(formFor.StringUtil.humanize(undefined)).toEqual('');
10 | expect(formFor.StringUtil.humanize('')).toEqual('');
11 | });
12 |
13 | it('should convert snake-case variables to humanized strings', function() {
14 | expect(formFor.StringUtil.humanize('snake_case')).toEqual('Snake Case');
15 | expect(formFor.StringUtil.humanize('snake_case_too')).toEqual('Snake Case Too');
16 | });
17 |
18 | it('should convert camel-case variables to humanized strings', function() {
19 | expect(formFor.StringUtil.humanize('camelCase')).toEqual('Camel Case');
20 | expect(formFor.StringUtil.humanize('camelCaseToo')).toEqual('Camel Case Too');
21 | });
22 |
23 | it('should not convert already-humanized strings', function() {
24 | expect(formFor.StringUtil.humanize('Word')).toEqual('Word');
25 | expect(formFor.StringUtil.humanize('Humanized String')).toEqual('Humanized String');
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/styles/default/checkbox-field.styl:
--------------------------------------------------------------------------------
1 | @require '_mixins';
2 | @require '_variables';
3 |
4 | checkbox-field {
5 | display: block;
6 | position: relative;
7 | }
8 |
9 | .form-for-field {
10 | > input[type="checkbox"] {
11 | @extend $form-for-hidden-input
12 |
13 | +label {
14 | cursor: pointer;
15 | display: inline-block;
16 |
17 | &:before {
18 | @extend $form-for-toggle-ui
19 |
20 | border-radius: 4px;
21 | content: " "; // Hidden
22 | }
23 | }
24 |
25 | &:focus + label:before {
26 | border-color: $border-color-focused;
27 | box-shadow: $box-shadow-focused;
28 | }
29 |
30 | &:checked + label:before {
31 | content: "\f00c";
32 | }
33 |
34 | &:disabled {
35 | opacity: 0;
36 | cursor: default;
37 | pointer-events: none;
38 |
39 | +label {
40 | cursor: default;
41 | opacity: $opacity-disabled;
42 |
43 | &:before {
44 | cursor: default;
45 | }
46 | }
47 | }
48 | }
49 |
50 | > input[type="checkbox"]:invalid,
51 | &.invalid > input[type="checkbox"] {
52 | +label:before {
53 | border-color: red;
54 | }
55 |
56 | &:focus + label:before {
57 | box-shadow: $box-shadow-error-focused;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/source/interfaces/bindable-field-wrapper.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Wrapper object for a form-field attribute that exposes field-state to field directives.
5 | *
6 | * Note that this interface exists for type-checking only; nothing actually implements this interface.
7 | */
8 | export class BindableFieldWrapper {
9 |
10 | /**
11 | * Input should 2-way bind against this attribute in order to sync data with formFor.
12 | */
13 | public bindable:any;
14 |
15 | /**
16 | * Input should disable itself if this value becomes true; typically this means the form is being submitted.
17 | */
18 | public disabled:boolean;
19 |
20 | /**
21 | * Input should display the string contained in this field (if one exists); this means the input value is invalid.
22 | */
23 | public error:string;
24 |
25 | /**
26 | * Unique identifier for field; can be used for WCAG compatibility (aria-* attributes).
27 | */
28 | public pristine:boolean;
29 |
30 | /**
31 | * Input should display a 'required' indicator if this value is true.
32 | */
33 | public required:boolean;
34 |
35 | /**
36 | * Field has been modified since initialization (or last reset via resetField/resetFields).
37 | */
38 | public uid:string;
39 | };
40 | };
--------------------------------------------------------------------------------
/styles/default/text-field.styl:
--------------------------------------------------------------------------------
1 | @require '_mixins';
2 | @require '_variables';
3 |
4 | text-field {
5 | display: block;
6 | }
7 |
8 | .form-for-field {
9 | input,
10 | textarea {
11 |
12 | @extend $form-for-input
13 |
14 | box-shadow: inset 0 1px 4px rgba(0,0,0, 0.15);
15 |
16 | &:focus {
17 | border-color: $border-color-focused;
18 | box-shadow: $box-shadow-focused;
19 | }
20 |
21 | &:disabled {
22 | opacity: $opacity-disabled;
23 | pointer-events: none;
24 | }
25 | }
26 |
27 | &.invalid input,
28 | &.invalid textarea,
29 | input:invalid
30 | textarea:invalid {
31 | border-color: red;
32 |
33 | &:focus {
34 | box-shadow: $box-shadow-error-focused;
35 | }
36 | }
37 |
38 | &.with-icon-before {
39 | input,
40 | textarea {
41 | padding-left: 40px;
42 | }
43 | }
44 |
45 | &.with-icon-after {
46 | input,
47 | textarea {
48 | padding-right: 40px;
49 | }
50 | }
51 | }
52 |
53 | .form-for-input-icon-left,
54 | .form-for-input-icon-right {
55 | position: absolute;
56 | bottom: 17px;
57 | width: 40px;
58 | text-align: center;
59 | line-height: 1em;
60 | margin-bottom: -.5em;
61 | }
62 |
63 | .form-for-input-icon-left {
64 | left: 0;
65 | }
66 |
67 | .form-for-input-icon-right {
68 | right: 0;
69 | }
70 |
--------------------------------------------------------------------------------
/source/directives/field-error.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | interface FieldErrorScope extends ng.IScope {
4 |
5 | /**
6 | * Error messages to display (or null if field is valid OR pristine)
7 | */
8 | error?:string;
9 |
10 | /**
11 | * Apply additional 'left-aligned' class to error message (useful for checkbox and radio items)
12 | */
13 | leftAligned?:boolean;
14 |
15 | /**
16 | * Optional UID for HTML element containing the error message string
17 | */
18 | uid?:string;
19 | }
20 |
21 | /**
22 | * Displays a standard formFor field validation error message.
23 | *
24 | * @example
25 | * // To display a field error:
26 | *
27 | *
28 | */
29 | export class FieldErrorDirective implements ng.IDirective {
30 |
31 | restrict:string = 'EA';
32 | templateUrl:string = ($element, $attributes) => {
33 | return $attributes['template'] || 'form-for/templates/field-error.html';
34 | };
35 |
36 | scope:any = {
37 | error: '=',
38 | leftAligned: '@?',
39 | uid: '@'
40 | };
41 |
42 | /* @ngInject */
43 | link($scope:FieldErrorScope):void {
44 | }
45 | }
46 |
47 | angular.module('formFor').directive('fieldError', () => {
48 | return new FieldErrorDirective();
49 | });
50 | }
--------------------------------------------------------------------------------
/examples/checkbox-field.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
22 |
23 |
46 |
47 |
--------------------------------------------------------------------------------
/styles/default/radio-field.styl:
--------------------------------------------------------------------------------
1 | @require '_mixins';
2 | @require '_variables';
3 |
4 | radio-field {
5 | display: block;
6 | position: relative;
7 | }
8 |
9 | .form-for-field {
10 | > label {
11 | display: block;
12 |
13 | > input[type="radio"] {
14 | @extend $form-for-hidden-input
15 |
16 | +span {
17 | cursor: pointer;
18 | display: inline-block;
19 |
20 | &:before {
21 | @extend $form-for-toggle-ui
22 |
23 | border-radius: 10px;
24 | content: " "; // Hidden
25 | font-size: 11px;
26 | }
27 | }
28 |
29 | &:focus + span:before {
30 | border-color: $border-color-focused;
31 | box-shadow: $box-shadow-focused;
32 | }
33 |
34 | &:checked + span:before {
35 | content: "\f111";
36 | }
37 |
38 | &:disabled {
39 | opacity: 0;
40 | cursor: default;
41 | pointer-events: none;
42 |
43 | +span {
44 | cursor: default;
45 | opacity: $opacity-disabled;
46 |
47 | &:before {
48 | cursor: default;
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | > label > input[type="radio"]:invalid,
56 | &.invalid > label > input[type="radio"] {
57 | +span:before {
58 | border-color: red;
59 | }
60 |
61 | &:focus + span:before {
62 | box-shadow: $box-shadow-error-focused;
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/examples/radio-field.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
27 |
28 |
51 |
52 |
--------------------------------------------------------------------------------
/templates/default/type-ahead-field.html:
--------------------------------------------------------------------------------
1 |
40 |
--------------------------------------------------------------------------------
/tests/integration/test-helper.js:
--------------------------------------------------------------------------------
1 | exports.assertElementIsClickable = function(element, opt_timeout) {
2 | var promise = protractor.ExpectedConditions.elementToBeClickable(element);
3 |
4 | return browser.wait(promise, opt_timeout || 100);
5 | };
6 |
7 | exports.assertElementIsNotClickable = function(element, opt_timeout) {
8 | return exports.assertElementIsClickable(element, opt_timeout).then(
9 | function() {
10 | throw Error('Element should not be clickable');
11 | },
12 | function() {
13 | // An element that is not clickable is what we want
14 | });
15 | };
16 |
17 | exports.assertFormDataValue = function(fieldName, expectedValue) {
18 | expect(exports.getFormDataValue(fieldName)).toBe(expectedValue);
19 | };
20 |
21 | exports.assertIsDisplayed = function(element, opt_timeout) {
22 | browser.wait(function () {
23 | return element.isPresent() &&
24 | element.isDisplayed();
25 | }, opt_timeout || 100);
26 | };
27 |
28 | exports.assertIsNotDisplayed = function(element) {
29 | return element.isDisplayed().then(
30 | function(isDisplayed) {
31 | if (isDisplayed) {
32 | throw Error('Element should not be displayed');
33 | }
34 | },
35 | function() {
36 | // An element not present in the DOM is not displayed (which is okay)
37 | });
38 | };
39 |
40 | exports.doMouseOver = function(element) {
41 | browser.actions().mouseMove(element).perform();
42 | };
43 |
44 | exports.getFormDataValue = function(fieldName) {
45 | return element(by.css('form')).evaluate('formData.' + fieldName);
46 | };
47 |
48 | exports.goToPage = function(url) {
49 | browser.driver.get(url);
50 | browser.driver.wait(browser.driver.isElementPresent(by.id('form')), 5000);
51 | };
--------------------------------------------------------------------------------
/templates/bootstrap/type-ahead-field.html:
--------------------------------------------------------------------------------
1 |
50 |
--------------------------------------------------------------------------------
/examples/select-field.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
29 |
30 |
61 |
62 |
--------------------------------------------------------------------------------
/styles/default/_mixins.styl:
--------------------------------------------------------------------------------
1 | @require '_variables';
2 |
3 | /****** Vender prefixes ******/
4 |
5 | placeholder-color($color) {
6 | &::-webkit-input-placeholder {
7 | color: $color;
8 | }
9 | &:-moz-placeholder {
10 | /* FF 4-18 */
11 | color: $color;
12 | }
13 | &::-moz-placeholder {
14 | /* FF 19+ */
15 | color: $color;
16 | }
17 | &:-ms-input-placeholder {
18 | /* IE 10+ */
19 | color: $color;
20 | }
21 | }
22 |
23 | user-select(val) {
24 | -ms-user-select: val;
25 | -moz-user-select: val;
26 | -webkit-user-select: val;
27 | }
28 |
29 | appearance(val) {
30 | -ms-appearance: val;
31 | -moz-appearance: val;
32 | -webkit-appearance: val;
33 | }
34 |
35 | /****** Shared base classes ******/
36 |
37 | $form-for-input {
38 | display: block;
39 | box-sizing: border-box;
40 | width: 100%;
41 | line-height: 1.5;
42 | padding: 6px 9px;
43 |
44 | font-family: inherit;
45 | font-size: inherit;
46 | text-align: left;
47 | color: inherit;
48 |
49 | border: $border;
50 | border-radius: $border-radius;
51 |
52 | appearance: none;
53 | outline: none;
54 | }
55 |
56 | // Should be hidden from user but remain tabbable and clickable
57 | // Note that display:none and visibility:hidden prevent tab/mouse interaction
58 | $form-for-hidden-input {
59 | position: absolute;
60 | opacity: 0; // Hidden but clickable
61 | z-index: 2; // Float above the styled, faux-input so mouse clicks will toggle selected state
62 | width: 20px;
63 | height: 20px;
64 | cursor: pointer;
65 | margin: 0;
66 | }
67 |
68 | $form-for-toggle-ui {
69 | position: absolute;
70 | height: 20px;
71 | width: 20px;
72 | top: 0;
73 | left: 0;
74 | width: 19px;
75 | padding-left: 1px; // Visually centers better
76 | line-height: 19px;
77 | text-align: center;
78 | vertical-align: middle;
79 | display: inline-block;
80 | background-image: linear-gradient(to top, $color-fill-1, white);
81 | border: $border;
82 | position: relative;
83 | margin-right: 5px;
84 | cursor: pointer;
85 | vertical-align: middle;
86 | font-family: FontAwesome;
87 | }
88 |
--------------------------------------------------------------------------------
/source/directives/collection-label.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * CheckboxField $scope.
5 | */
6 | interface CollectionLabelScope extends ng.IScope {
7 |
8 | /**
9 | * Name of collection attribute.
10 | */
11 | attribute?:string;
12 |
13 | /**
14 | * Bindable label for template to display.
15 | */
16 | bindableLabel?:string;
17 |
18 | /**
19 | * Optional help tooltip to display on hover.
20 | * By default this makes use of the Angular Bootstrap tooltip directive and the Font Awesome icon set.
21 | */
22 | help?:string;
23 |
24 | /**
25 | * Incoming (user-specified) label.
26 | * This value is passed along to 'bindableLabel' to be consumed by the associated template.
27 | * This field is allowed to contain markup.
28 | */
29 | label?:string;
30 |
31 | /**
32 | * Shared between formFor and CollectionLabel directives.
33 | */
34 | model?:BindableCollectionWrapper;
35 | }
36 |
37 | var $sce_:ng.ISCEService;
38 |
39 | /**
40 | * Header label for collections.
41 | * This component displays header text as well as collection validation errors.
42 | *
43 | * @example
44 | * // To display a simple collection header:
45 | *
46 | *
47 | *
48 | * @param $sce $injector-supplied $sce service
49 | */
50 | export class CollectionLabelDirective implements ng.IDirective {
51 |
52 | require:string = '^formFor';
53 | restrict:string = 'EA';
54 | templateUrl:string = ($element, $attributes) => {
55 | return $attributes['template'] || 'form-for/templates/collection-label.html';
56 | };
57 |
58 | scope:any = {
59 | attribute: '@',
60 | help: '@?',
61 | label: '@'
62 | };
63 |
64 | /* @ngInject */
65 | constructor($sce:ng.ISCEService) {
66 | $sce_ = $sce;
67 | }
68 |
69 | /* @ngInject */
70 | link($scope:CollectionLabelScope,
71 | $element:ng.IAugmentedJQuery,
72 | $attributes:ng.IAttributes,
73 | formForController:FormForController):void {
74 |
75 | $scope.$watch('label', function(value) {
76 | $scope.bindableLabel = $sce_.trustAsHtml(value);
77 | });
78 |
79 | $scope.model = formForController.registerCollectionLabel($scope.attribute);
80 | }
81 | }
82 |
83 | angular.module('formFor').directive('collectionLabel', ($sce) => {
84 | return new CollectionLabelDirective($sce);
85 | });
86 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This repository is no longer actively maintained.
2 |
3 | Issue reports and pull requests will probably not be attended.
4 |
5 | I am no longer working with Angular on a regular basis. My day job has switched to React and it's too much effort to context switch between the frameworks. Given the upcoming Angular 2.0 release it seems like a reasonable time to end support for this library.
6 |
7 | Thanks to all of you for using, supporting, and contributing to this project.
8 |
9 | # angular-form-for [](https://travis-ci.org/bvaughn/angular-form-for) [](https://gitter.im/bvaughn/angular-form-for?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10 |
11 | *formFor* is a quick and easy way to declare complex HTML forms with client and server-side validations.
12 | You can generate a complete form with as little markup as this:
13 |
14 | ```html
15 |
16 | ```
17 |
18 | But that's not all! *formFor* is incredibly flexible, offering a wide range of configuration options.
19 | Check out the official website to learn more:
20 | [http://bvaughn.github.io/angular-form-for/](http://bvaughn.github.io/angular-form-for/)
21 |
22 | ## Compatibility and Dependencies
23 |
24 | *formFor* is compatible with Angular Angular 1.2 and newer. It does not require any third party libraries such as jQuery, lodash, or underscore.
25 |
26 | ## Installation
27 |
28 | You can install this plugin with either [Bower](http://bower.io/) or [NPM](https://www.npmjs.org/):
29 |
30 | ```shell
31 | bower install angular-form-for --save-dev
32 | npm install angular-form-for --save-dev
33 | ```
34 |
35 | This will download an `angular-form-for` folder into your bower/node components directory. Inside of that folder there will be a `dist` folder with the *formFor* JavaScript and CSS files. By default *formFor* is compatible with [Bootstrap](getbootstrap.com) 3.2.x styles. A separate, *formFor* only CSS stylehseet is included for those not using Bootstrap.
36 |
37 | Lastly just include the *formFor* module in your Angular application like so:
38 |
39 | ```js
40 | angular.module('myAngularApp', ['formFor']);
41 | ```
42 |
43 | ## Contributions
44 |
45 | Interested in contributing? Check out the [contribution guidelines](CONTRIBUTING.md)!
46 |
47 | ## License
48 |
49 | Copyright (c) 2014 Brian Vaughn. Licensed under the MIT license.
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-form-for",
3 | "version": "4.1.12",
4 | "description": "Set of Angular directives to simplify creating and validating HTML forms.",
5 | "keywords": [
6 | "angular",
7 | "form",
8 | "forms",
9 | "crud",
10 | "validation"
11 | ],
12 | "main": "gulpfile.js",
13 | "directories": {
14 | "test": "tests"
15 | },
16 | "dependencies": {},
17 | "devDependencies": {
18 | "angular": "~1.3.15",
19 | "angular-animate": "~1.3.15",
20 | "angular-aria": "~1.3.15",
21 | "angular-bootstrap-npm": "~0.12.3",
22 | "angular-material": "0.10.0",
23 | "angular-mocks": "~1.3.15",
24 | "angular-route": "^1.3.15",
25 | "angular-ui-router": "^0.2.13",
26 | "autoprefixer-stylus": "~0.5.0",
27 | "bootstrap": "^3.3.4",
28 | "doxx": "~1.2.5",
29 | "font-awesome": "^4.3.0",
30 | "gulp": "^3.9.0",
31 | "gulp-angular-protractor": "0.0.2",
32 | "gulp-angular-templatecache": "~1.5.0",
33 | "gulp-clean": "~0.3.1",
34 | "gulp-closure-deps": "~0.4.0",
35 | "gulp-concat": "~2.5.2",
36 | "gulp-doxx": "0.0.4",
37 | "gulp-karma": "0.0.4",
38 | "gulp-ng-annotate": "~0.5.2",
39 | "gulp-rename": "~1.2.0",
40 | "gulp-replace": "^0.5.3",
41 | "gulp-shell": "~0.3.0",
42 | "gulp-stylus": "~2.0.1",
43 | "gulp-tsc": "~0.9.2",
44 | "gulp-uglify": "~1.1.0",
45 | "gulp-umd": "~0.1.3",
46 | "html2js": "~0.1.1",
47 | "jasmine": "2.1.1",
48 | "jasmine-object-matchers": "0.0.3",
49 | "jasmine-promise-matchers": "0.0.5",
50 | "jquery": "~2.1.3",
51 | "karma": "~0.12.31",
52 | "karma-jasmine": "~0.3.5",
53 | "karma-jasmine-ajax": "~0.1.11",
54 | "karma-ng-html2js-preprocessor": "~0.1.2",
55 | "karma-phantomjs-launcher": "~0.1.4",
56 | "nib": "~1.1.0",
57 | "phantomjs": "~1.9.13",
58 | "protractor": "^2.0.0",
59 | "replace": "^0.3.0",
60 | "run-sequence": "~1.0.2",
61 | "uglify-js": "~2.4.17",
62 | "uglify-js2": "~2.1.11"
63 | },
64 | "scripts": {
65 | "prestart": "npm install",
66 | "start": "http-server -p 8000",
67 | "unit": "gulp test:unit",
68 | "update-webdriver": "webdriver-manager update",
69 | "preprotractor": "npm run update-webdriver",
70 | "protractor": "protractor protractor.conf.js"
71 | },
72 | "repository": {
73 | "type": "git",
74 | "url": "https://github.com/bvaughn/angular-form-for.git"
75 | },
76 | "author": "Brian Vaughn ",
77 | "license": "MIT",
78 | "bugs": {
79 | "url": "https://github.com/bvaughn/angular-form-for/issues"
80 | },
81 | "homepage": "https://github.com/bvaughn/angular-form-for"
82 | }
83 |
--------------------------------------------------------------------------------
/source/interfaces/builder/view-field.ts:
--------------------------------------------------------------------------------
1 | module formFor {
2 |
3 | /**
4 | * Describes the expected input UI for an individual model field.
5 | */
6 | export interface ViewField {
7 |
8 | /**
9 | * Attribute name within form data object (e.g. "username" within {username: "John Doe"}).
10 | * This is a convenience attribute added by Forms JS based on the map key in {@link ViewSchema}.
11 | * @private
12 | */
13 | key_:string;
14 |
15 | /**
16 | * An empty/blank selection should be allowed.
17 | * This property is only supported for {@link BuilderFieldType.SELECT} inputs.
18 | */
19 | allowBlank?:boolean;
20 |
21 | /**
22 | * Enable filtering of list via a text input at the top of the drop-down.
23 | * This property is only supported for {@link BuilderFieldType.SELECT} inputs.
24 | */
25 | enableFiltering?:boolean;
26 |
27 | /**
28 | * Optional help text providing additional context to users.
29 | */
30 | help?:string;
31 |
32 | /**
33 | * Input type used by this field.
34 | * This is a required field.
35 | */
36 | inputType?:BuilderFieldType;
37 |
38 | /**
39 | * Field ; defaults to humanized form of attribute name (e.g. "firstName" becomes "First Name").
40 | */
41 | label?:string;
42 |
43 | /**
44 | * Optional override for label key in options array; defaults to "label".
45 | * This property is only supported for {@link BuilderFieldType.SELECT} inputs.
46 | */
47 | labelAttribute?:string;
48 |
49 | /**
50 | * Designates a text input as multi-line (