{"id":25707709,"url":"https://github.com/jhsware/inferno-formlib","last_synced_at":"2026-03-08T23:31:15.121Z","repository":{"id":57273589,"uuid":"88621386","full_name":"jhsware/inferno-formlib","owner":"jhsware","description":"Bootstrap 4 compatible form generation library for Inferno.js using isomorphic-schema definitions.","archived":false,"fork":false,"pushed_at":"2020-09-01T18:26:57.000Z","size":351,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-02T02:22:30.189Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhsware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-18T12:16:34.000Z","updated_at":"2020-09-01T18:26:55.000Z","dependencies_parsed_at":"2022-09-17T02:23:01.456Z","dependency_job_id":null,"html_url":"https://github.com/jhsware/inferno-formlib","commit_stats":null,"previous_names":[],"tags_count":132,"template":false,"template_full_name":null,"purl":"pkg:github/jhsware/inferno-formlib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhsware%2Finferno-formlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhsware%2Finferno-formlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhsware%2Finferno-formlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhsware%2Finferno-formlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhsware","download_url":"https://codeload.github.com/jhsware/inferno-formlib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhsware%2Finferno-formlib/sbom","scorecard":{"id":519149,"data":{"date":"2025-08-11","repo":{"name":"github.com/jhsware/inferno-formlib","commit":"a8b71b33a82094e291c003d96b3a35e934559289"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-20T02:32:29.047Z","repository_id":57273589,"created_at":"2025-08-20T02:32:29.047Z","updated_at":"2025-08-20T02:32:29.047Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30276905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-25T08:38:37.314Z","updated_at":"2026-03-08T23:31:15.095Z","avatar_url":"https://github.com/jhsware.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# inferno-formlib\n[![Build Status](https://travis-ci.org/jhsware/inferno-formlib.svg?branch=v0.2.24)](https://travis-ci.org/jhsware/inferno-formlib)\n[![gzip size](http://img.badgesize.io/https://unpkg.com/inferno-formlib@6.0.5/dist/index.cjs.js?compression=gzip)](https://unpkg.com/inferno-formlib@6.0.5/dist/index.cjs.js)\n\nThe goal of this project is to create a bootstrap 4 compatible form generation library for Inferno.js using isomorphic-schema definitions.\n\n## Currently maintained versions\ninferno-formlib 7.x supports Inferno v7\ninferno-formlib 5.x supports Inferno v5\n\n## Example With Sticky Action Bar\nThis is the basic anatomy of a form generated with inferno-formlib. It can generate nested forms from isomorphic-schema form definitions and list fields support drag'n'drop reordering.\n\n```JavaScript\nimport { Component } from 'inferno'\n\n// Imports to define form schema\nimport { Schema } from 'isomorphic-schema'\nimport TextField from 'isomorphic-schema/lib/field_validators/TextField'\nimport DateField from 'isomorphic-schema/lib/field_validators/DateField'\n\n// Register widgets\nimport 'inferno-formlib/dist/widgets/InputField'\nimport 'inferno-formlib/dist/widgets/DateField'\n\n// Form generation\nimport { FormRows } from 'inferno-formlib'\nimport { ActionBar } from 'inferno-formlib/dist/widgets/ActionBar'\n\n// Some useful Bootstrap components\nimport Form from 'inferno-bootstrap/dist/Form/Form'\nimport Button from 'inferno-bootstrap/dist/Button'\nimport Row from 'inferno-bootstrap/dist/Row'\nimport Col from 'inferno-bootstrap/dist/Col'\n\nconst formSchema = new Schema('Form Schema', {\n    title: new TextField({\n      label: 'Race Name' \n    }),\n    startDate: new DateField({\n      label: 'Start Date'\n    })\n  })\n})\n\nclass FormEdit extends Component {\n  constructor (props) {\n    super(props)\n\n    this.didChange = this.didChange.bind(this)\n    this.doSubmit = this.doSubmit.bind(this)\n\n    this.state = {\n      validationErrors: undefined,\n      isMounted: false, // Prevents animations on mounting of form\n      value: {}\n    }\n  }\n\n  componentDidMount () {\n    this.setState({\n      isMounted: true\n    })\n  }\n\n  didChange (propName, value) {\n    const newValue = this.state.value\n    newValue[propName] = value\n    this.setState({\n      value: newValue\n    })\n  }\n\n  doSubmit (e) {\n    e.preventDefault()\n    const validationErrors = formSchema.validate(this.state.value)\n    this.setState({\n      validationErrors\n    })\n\n    if (validationErrors === undefined) {\n      // TODO: Submit form to API\n    } else {\n      // TODO: Show error message\n    }\n  }\n\n  render () {\n    return (\n      \u003cForm onSubmit={this.doSubmit}\u003e\n        \u003cRow\u003e\n          \u003cCol\u003e\n            \u003ch2\u003eMy Form\u003c/h2\u003e\n          \u003c/Col\u003e\n        \u003c/Row\u003e\n\n        \u003cFormRows\n          schema={formSchema}\n          validationErrors={this.state.validationErrors}\n          value={this.state.value}\n          isMounted={this.state.isMounted}\n          onChange={this.didChange}\n         /\u003e\n\n        \u003cActionBar boundary={{top: 0, bottom: 0}}\u003e\n          \u003cRow\u003e\n              \u003cCol\u003e\n                \u003cButton type=\"submit\" color=\"success\"\u003eSave\u003c/Button\u003e\n              \u003c/Col\u003e\n          \u003c/Row\u003e\n        \u003c/ActionBar\u003e\n      \u003c/Form\u003e\n    )\n  }\n}\n```\n\n```CSS\n.InfernoFormlib-ActionBar {\n    background-color: rgba(255,255,255,0.8);\n    z-index: 1;\n    padding: 0.5rem 1rem;\n    width: 100%;\n    border-top: 1px solid #777;\n}\n.InfernoFormlib-StickyActionBar {\n    position: fixed;\n}\n.InfernoFormlib-ActionBar--hidden {\n    visibility: hidden;\n}\n.InfernoFormlib-StickyActionBar--hidden {\n    display: none;\n}\n\n```\n\n## Form Demos\n\nTo see form demos:\n\n```sh\n$ git clone git@github.com:jhsware/inferno-formlib.git\n\n$ cd inferno-formlib\n\n$ npm i \u0026\u0026 npm run build-test\n\n$ node test/browser/server.js\n``` \n\nYou can now access the examples in your browser at http://localhost:8080\n\nThe package generates your form rows and calls an onChange handler whenever the form is updated.\n\n## Installation\n\n```sh\n$ npm i -S inferno-formlib isomorphic-schema component-registry\n```\n\nTo use the components without requiring transpilation you import from the `/dist` directory:\n\n```JavaScript\nimport { FormRows } from 'inferno-formlib/dist/FormRows'\n```\n \nYou can get a nicer debugging experience by importing your components from the original source code in the `/lib` directory. However this requires that you transpile `node_module/inferno-formlib` imports and add the contents of the .babelrc config file from this repos to your project:\n\n```JavaScript\nimport { FormRows } from 'inferno-formlib/lib/FormRows'\n```\n\nYou will find a working webpack.config file in the folder `test/browser`. Don't forget to add your .babelrc\nfile and babel package devDepencies.\n\n## Another Example\nMore examples can be found at https://github.com/jhsware/inferno-formlib/tree/master/test/browser/src\n\nYou will find some standard form css if you look at https://github.com/jhsware/inferno-formlib/blob/master/test/browser/app.css\n\nAnimations are done with https://github.com/jhsware/inferno-animation\n\n```jsx\nimport { Component } from 'inferno'\n\n// Form schema definition\nimport { Schema } from 'isomorphic-schema'\nimport TextField from 'isomorphic-schema/lib/field_validators/TextField'\nimport EmailField from 'isomorphic-schema/lib/field_validators/EmailField'\nimport IntegerField from 'isomorphic-schema/lib/field_validators/IntegerField'\nimport TextAreaField from 'isomorphic-schema/lib/field_validators/TextAreaField'\n\n// Widgets need to be imported so they can be found by inferno-formlib\n// we import them one-by-one to reduce bundle size.\nimport 'inferno-formlib/dist/widgets/InputField'\nimport 'inferno-formlib/dist/widgets/TextAreaField'\nimport 'inferno-formlib/dist/widgets/FormRow'\nimport { FormRows } from 'inferno-formlib/dist/FormRows'\n\n// Some bootstrap stuff...\nimport Button from 'inferno-bootstrap/dist/Button'\nimport Col from 'inferno-bootstrap/dist/Col'\nimport Form from 'inferno-bootstrap/dist/Form/Form'\nimport Row from 'inferno-bootstrap/dist/Row'\n\nconst formSchema = new Schema('Form Schema', {\n  title: new TextField({\n    label: 'Title',\n    placeholder: 'Type here...',\n    required: true\n  }),\n  email: new EmailField({\n    label: 'E-mail',\n    placeholder: 'person@email.com',\n    required: true\n  }),\n  age: new IntegerField({\n    label: 'Age',\n    placeholder: 'i.e. 16',\n    required: true\n  }),\n  bio: new TextAreaField({\n    label: 'Bio',\n    placeholder: 'Type here...',\n    help: 'This \u003cb\u003ewill be\u003c/b\u003e rendered as HTML',\n    required: true\n  })\n})\n\nexport default class FormSection extends Component {\n\n  constructor (props) {\n    super(props)\n\n    this.state = {\n        value: {},\n        validationError: undefined\n    }\n\n    this.didChange = this.didChange.bind(this)\n    this.doSubmit = this.doSubmit.bind(this)\n  }\n\n  doSubmit (e) {\n    e.preventDefault()\n    const errors = formSchema.validate(this.state.value)\n    this.setState({\n      validationError: errors\n    })\n  }\n\n  didChange (propName, value) {\n    const val = this.state.value\n    val[propName] = value\n    this.setState({\n        value: val\n    })\n    // This is where you would call this.props.onChange\n  }\n\n  render () {\n    return (\n      \u003cForm onSubmit={this.doSubmit}\u003e\n        \u003cRow\u003e\n          \u003cCol\u003e\n            \u003cFormRow\n              renderHelpAsHtml={true}\n              schema={formSchema}\n              validationErrors={this.state.validationError}\n              value={this.state.value}\n              onChange={this.didChange} /\u003e\n          \u003c/Col\u003e\n        \u003c/Row\u003e\n        \u003cRow\u003e\n          \u003cCol\u003e\n            \u003cButton type=\"submit\"\u003eSave\u003c/Button\u003e\n          \u003c/Col\u003e\n        \u003c/Row\u003e\n      \u003c/Form\u003e\n    )\n  }\n}\n```\n\n## Customising How Rows are Rendered\nThis example shows how you create a character limit counter for text fields. You do this by customising how the row is rendered by means of a row widget adapter. The row widget adapter is registered in the globalRegistry and will override the existing generic row widget used to render text input fields.\n\nNote that this approach will override the look and feel of all TextField rows.\n\n```JavaScript\nimport { Component } from 'inferno'\nimport { findDOMNode } from 'inferno-extras'\n\nimport { Adapter, globalRegistry } from 'component-registry'\n\nimport { interfaces, i18n } from 'isomorphic-schema'\nimport { IFormRowWidget }  from 'inferno-formlib/dist/interfaces'\n\nimport { ErrorMsg, HelpMsg, Label } from 'inferno-formlib/dist/widgets/FormRow'\nimport { animateOnAdd, animateOnRemove } from 'inferno-animation'\nimport FormText from 'inferno-bootstrap/dist/Form/FormText'\nimport FormGroup from 'inferno-bootstrap/dist/Form/FormGroup'\n\nimport { renderString } from 'inferno-formlib/dist/widgets/common'\n\nfunction CharsLeft (props) {\n  const outp = renderString(i18n('isomorphic-schema--field_charactersLeft'), props.options \u0026\u0026 props.options.lang, 'Tecken kvar: ${charsLeft}')\n  const color = (props.charsLeft \u003c 0 ? 'danger' : undefined)\n\n  return \u003cFormText muted color={color} className=\"CharsLeft\" for={props.id}\u003e{outp.replace('${charsLeft}', props.charsLeft)}\u003c/FormText\u003e\n}\n\n/*\n    PROPS:\n    - animation: animation css class prefix\n    - submitted: bool, has been submitted\n    - field:  isomorphic-schema field validator object\n    - errors: isomorphic-schema field and server error object { fieldErrors, serverErrors } or undefined if no errors\n    - id:     unique id of field\n*/\nclass Row extends Component {\n  // TODO: Add animation support\n\n  // support required\n  componentDidMount () {\n      if (this.props.formIsMounted) {\n          animateOnAdd(findDOMNode(this), 'InfernoFormlib-Row--Animation')\n      }\n  }\n\n  componentWillUnmount () {\n      animateOnRemove(findDOMNode(this), 'InfernoFormlib-Row--Animation')\n  }\n\n  render () {\n    const field = this.props.adapter.context\n    const value = this.props.value\n\n    let charsLeft\n    if (field._maxLength) {\n      charsLeft = (typeof value === 'string' ? field._maxLength - value.length : field._maxLength)\n    }\n\n    return (\n      \u003cFormGroup id={this.props.namespace.join('.') + '__Row'}\u003e\n        {field.label \u0026\u0026 \u003cLabel id={this.props.id}\u003e{field.label}\u003c/Label\u003e}\n        \u003cdiv className=\"InfernoFormlib-RowFieldContainer\"\u003e\n            {this.props.children}\n        \u003c/div\u003e\n        {this.props.validationError ? \u003cErrorMsg field={field} validationError={this.props.validationError} submitted={this.props.submitted} /\u003e : null}\n        {(charsLeft !== undefined) \u0026\u0026 \u003cCharsLeft charsLeft={charsLeft} /\u003e}\n        {field.help \u0026\u0026 \u003cHelpMsg field={field} text={field.help} required={field._isRequired} /\u003e}\n      \u003c/FormGroup\u003e\n    )\n  }\n}\n\nnew Adapter({\n  implements: IFormRowWidget,\n  adapts: interfaces.ITextField,\n  \n  Component: Row\n})\n\n```\n\n## i18n Support\nTo add translations, you can add a translation utility which implements ITranslationUtil.\nUse string template style variables to output options from the field definition.\n\n```JavaScript\nimport { interfaces } from 'inferno-formlib'\nimport { Utility } from 'component-registry'\n\nexport default new Utility({\n  implements: interfaces.ITranslationUtil,\n  message (label, lang) {\n    // Use 'en' as fallback language\n    const langDict = lang[lang] || lang['en']\n    // Use label as fallback string\n    return langDict[label] || label\n  }\n})\n\n/* eslint-disable */\nvar en = {\n  'isomorphic-schema--field_required': 'Required',\n  'isomorphic-schema--text_field_too_short': 'The text is too short. Min ${minLength} chars.'\n}\n\nvar sv = {\n  'isomorphic-schema--field_required': 'Obligatorisk',\n  'isomorphic-schema--text_field_too_short': 'Texten är för kort. Minst ${minLength} tecken.'\n}\n\nvar fr = {\n  'isomorphic-schema--field_required': 'Obligatoire',\n  'isomorphic-schema--text_field_too_short': 'Le texte est trop court. Au moins ${minLength} caractères.'\n}\n\nvar lang = { en, sv, fr }\n```\n\n## Creating a Widget\nFor now, check the code at https://github.com/jhsware/inferno-formlib/tree/master/test/browser/src/ImageUploadWidget\n\n### Creating an AutoComplete Widget\nThere is an AutoComplete wudget that you can use as a base for your own autocomplete. First \nyou need to create a new `isomorphic-schema`field. We are assuming that the underlying value\nis an object that has the form:\n\n```JavaScript\nconst obj = {\n  id: 'asdfg',\n  theTitle: 'Yada Yada'\n}\n```\n\nThe data flows through the widget and field like this:\n\n```\nValue passed to field widget:\n\n  props.value -\u003e field.toFormattedString() -\u003e state.text ...\n\nValue rendered in field widget input control:\n\n  state.text -\u003e input.value\n\nOption selected from list:\n\n  getOptions -\u003e options -\u003e select an option -\u003e field.fromString() -\u003e props.onChange() -\u003e props.value ...\n\nText entered in input control:\n\n  onInput() -\u003e  e.target.value -\u003e state.text -\u003e input\n  \n```\n\n```JavaScript\nimport { globalRegistry, createObjectPrototype, createInterface } from 'component-registry'\nimport axios from 'axios'\n\nimport DynamicSelectAsyncBaseField from 'isomorphic-schema/lib/field_validators/DynamicSelectAsyncBaseField'\nimport TextField from 'isomorphic-schema/lib/field_validators/TextField'\nimport ObjectField from 'isomorphic-schema/lib/field_validators/ObjectField'\nimport { Schema } from 'isomorphic-schema';\n\nimport AutoComplete from 'inferno-formlib/dist/widgets/AutoComplete'\nimport { IInputFieldWidget } from 'inferno-formlib/dist/interfaces'\n\nexport const IMySelectAsyncField = createInterface({\n  name: 'IMySelectAsyncField'\n})\n\nconst userSchema = new Schema('User Schema', {\n  id: new TextField({}),\n  theTitle: new TextField({})\n})\n\nexport const MySelectAsyncField = createObjectPrototype({\n  implements: [IMySelectAsyncField],\n  extends: [DynamicSelectAsyncBaseField],\n\n  constructor (options) {\n    this._IDynamicSelectAsyncBaseField.constructor.call(this, options)\n    this.valueType = new ObjectField({\n      schema: userSchema,\n      required: true\n    })\n  },\n\n  validateAsync (inp, options, context) {\n    const promise = this._IDynamicSelectAsyncBaseField.validateAsync.call(this, inp)\n    return promise.then(function (error) {\n      if (error) {\n        return Promise.resolve(error)\n      } else {\n        // We could validate the data further here by this.valueType.validate(inp),\n        // but skipping because the value is selected and we don't have any fancy\n        // validation rules ATM. You could also go one step further and check that\n        // the value actually exists in your backend. Just make sure you don't kill your\n        // backend API...\n        return Promise.resolve(undefined)\n      }\n    })\n  },\n\n  getOptionsAsync (inp, options, context) {\n    // This should return a list of objects [{ name: 'maps to obj.id', 'title': 'maps to obj.theTitle'}]\n    return axios.get('https://some.url/endpoint/to/options', {q: options.search}).then((res) =\u003e return res.data)\n  },\n\n  getOptionTitleAsync (inp, options, context) {\n    return this.getOptionsAsync(inp, options, context)\n      .then(user =\u003e {\n        const find = user.find(x =\u003e user.name === inp)\n        return Promise.resolve(find.title)\n      }).catch(err =\u003e {\n        return Promise.reject(undefined)\n      })\n  },\n\n  toFormattedString (inp) {\n    // Convert data from data model to internal representation \n    if (inp) {\n      return {\n        name: inp.id,\n        title: inp.theTitle\n      }\n    }\n  },\n\n  fromString (inp) {\n    // Convert data from selected value in dropdown list to\n    // object value in data model\n    if (inp) {\n      return {\n        id: inp.name,\n        theTitle: inp.title\n      }\n    }\n  }\n})\n\nnew Adapter({\n  implements: IInputFieldWidget,\n  adapts: IMySelectAsyncField,\n  Component: AutoComplete\n})\n```\n\nNow you can use your new field in form schemas or ObjectPrototype interfaces. NOTE: When rendering forms with async\nfields you need to call `mySchema.validateAsync` when validating.\n\n## Custom Widgets\nCustom widgets override whatever standard widget would be rendered for a specific field in form. This is useful\nif you want a different behaviour for a field in one specific form.\n\nTODO: Explain how to use a custom widget in a form\n\n## Manually Created Forms\nYou can see an example of a manually created form at https://github.com/jhsware/inferno-formlib/blob/master/test/browser/src/DatePage.js\n\nTODO: Explain how to use widgets for manual creation of forms\n\n## Transpiling\nMake sure you have the following in your .babelrc file (you probably do) and allow transpiling of the inferno-formlib node module:\n\n```json\n{\n  \"presets\": [\"es2015\", \"stage-0\"],\n  \"plugins\": [\n      [\n        \"babel-plugin-inferno\",\n        {\n          \"imports\": true\n        }\n      ]\n    ]\n}\n```\n\n\n# Dev Notes\n\n## Distribution\n\nmain: '', // CommonJS module transpiled to ES5. Can be consumed by webpack or Node.js as is\nmodule: '', // ES6 module with import/export but transpiled to ES5\nesnext: '', // ES6 code\nhttps://github.com/rollup/rollup/wiki/pkg.module\n\nSide effects:\nhttps://webpack.js.org/guides/tree-shaking/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhsware%2Finferno-formlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhsware%2Finferno-formlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhsware%2Finferno-formlib/lists"}