{"id":13481330,"url":"https://github.com/guillotinaweb/ngx-schema-form","last_synced_at":"2025-05-14T10:06:27.343Z","repository":{"id":37849790,"uuid":"60182693","full_name":"guillotinaweb/ngx-schema-form","owner":"guillotinaweb","description":"HTML form generation based on JSON Schema","archived":false,"fork":false,"pushed_at":"2024-11-21T18:47:06.000Z","size":3743,"stargazers_count":483,"open_issues_count":125,"forks_count":172,"subscribers_count":48,"default_branch":"master","last_synced_at":"2025-04-26T10:26:43.028Z","etag":null,"topics":["angular","angular2","json-schema"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guillotinaweb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-06-01T14:11:25.000Z","updated_at":"2025-03-21T21:08:48.000Z","dependencies_parsed_at":"2024-06-18T14:04:53.153Z","dependency_job_id":"5a0ab0b2-48be-469c-86b5-bc88aad92377","html_url":"https://github.com/guillotinaweb/ngx-schema-form","commit_stats":{"total_commits":635,"total_committers":55,"mean_commits":"11.545454545454545","dds":0.6645669291338583,"last_synced_commit":"114337d075580f7bad9f734d5d02bb8b0ed403bf"},"previous_names":["makinacorpus/angular2-schema-form","makinacorpus/ngx-schema-form"],"tags_count":97,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillotinaweb%2Fngx-schema-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillotinaweb%2Fngx-schema-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillotinaweb%2Fngx-schema-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillotinaweb%2Fngx-schema-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guillotinaweb","download_url":"https://codeload.github.com/guillotinaweb/ngx-schema-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252571773,"owners_count":21769887,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["angular","angular2","json-schema"],"created_at":"2024-07-31T17:00:50.911Z","updated_at":"2025-05-14T10:06:27.289Z","avatar_url":"https://github.com/guillotinaweb.png","language":"TypeScript","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# Ngx Schema Form [![Build Status](https://github.com/guillotinaweb/ngx-schema-form/workflows/CI/badge.svg)](https://github.com/guillotinaweb/ngx-schema-form/actions?query=workflow%3ACI)\n\nNgx Schema Form is an Angular 2+ module allowing you to instanciate an HTML form from a [JSON schema](http://json-schema.org/).\n\nNote: Version 1.x is compliant with Angular \u003c=4, version 2.x is compliant with Angular \u003e=6.\n\n## DISCLAIMER\n\nNgx Schema Form is **not** related to [angular-schema-form](https://github.com/json-schema-form/angular-schema-form) and [schemaform.io](http://schemaform.io/).\n\nWe think `angular-schema-form` is a great Angular 1 library, and when it will move to Angular 2+, we will probably join our efforts to produce and maintain a unique Angular 2+ solution.\n\n## Demo\n\n[Demo](https://guillotinaweb.github.io/ngx-schema-form/)\n\n## Features\n\n- Generate a form from a single json schema object\n- Generate a form from a default set of html constructs\n- Allow initialization from previous values\n- Validation handled by z-schema\n- Allow injection of custom validators\n- Allow declaration of custom widgets\n- Allow injection of custom bindings (new!)\n\n## Installation\n\nTo use Ngx Schema Form in your project simply execute the following command:\n\n```bash\nnpm install ngx-schema-form --save\n```\n\nYou just have to check that all the peer-dependencies of this module are satisfied in your package.json.\n\n##### JSON Schema\n\nWith the installation there comes a JSON-Schema file that declares all specific or additional\nproperties supported by _ngx-schema-form_.\n\nWhen using `*.json` files you may declare it with the `$schema` property to let your IDE's autocompletion help you create a schema-form.\n\n```bash\n{\n  \"$schema\": \"./node_modules/ngx-schema-form/ngx-schema-form-schema.json\",\n  \"title\": \"My awesome schema-form\"\n  ...\n}\n\n```\n\n## Getting started\n\nHere our goal will be to create a simple login form.\nLet's start by creating a simple AppComponent taking a simple JSON schema as input.\n\n```js\n// app.component.ts\n\nimport { Component } from \"@angular/core\";\nimport { ISchema } from 'ngx-schema-form';\n\n@Component({\n  selector: \"minimal-app\",\n  // Bind the \"mySchema\" member to the schema input of the Form component.\n  template: '\u003csf-form [schema]=\"mySchema\"\u003e\u003c/sf-form\u003e',\n})\nexport class AppComponent {\n  // The schema that will be used to generate a form\n  mySchema: ISchema = {\n    properties: {\n      email: {\n        type: \"string\",\n        description: \"email\",\n        format: \"email\",\n      },\n      password: {\n        type: \"string\",\n        description: \"Password\",\n      },\n      rememberMe: {\n        type: \"boolean\",\n        default: false,\n        description: \"Remember me\",\n      },\n    },\n    required: [\"email\", \"password\", \"rememberMe\"],\n  };\n}\n```\n\nCreate a module which import the AppComponent and configure Ngx schema form.\n\n```js\n//app.module.ts\n\nimport { NgModule } from \"@angular/core\";\nimport { BrowserModule } from \"@angular/platform-browser\";\nimport {\n  SchemaFormModule,\n  WidgetRegistry,\n  DefaultWidgetRegistry,\n} from \"ngx-schema-form\";\nimport { AppComponent } from \"./app.component\";\n\n@NgModule({\n  imports: [SchemaFormModule.forRoot(), BrowserModule],\n  declarations: [AppComponent],\n  providers: [{ provide: WidgetRegistry, useClass: DefaultWidgetRegistry }],\n})\nexport class AppModule {}\n```\n\nThe code above creates a form with three required fields.\nThe validation state of each field is reflected by the class of each of them which can be either \"has-error\" or \"has-success\".\nValidation is done everytime a field's value changes.\nBasic validation is made by testing the value of the field against its corresponding schema.\nThe input schema support almost all the features listed on the [JSON schema specification](http://json-schema.org/).\n\n### Accessing the form's value\n\n#### Input binding\n\nIt is possible to provide initial values to the form.\nYou can set the initial form's value through the `model` input:\n\n```js\n@Component({\ntemplate: '\u003csf-form [schema]=\"mySchema\" [model]=\"myModel\"\u003e\u003c/sf-form\u003e'\n})\nexport class AppComponent {\n  mySchema = {...};\n  myModel = {email:\" john.doe@example.com\"};\n}\n```\n\n#### Output binding\n\nThe Form component provides the `onChange` output binding of which value represents the value of the form.\nFor instance, you can display the current forms's value with the following template:\n\n```js\ntemplate: '\u003csf-form [schema]=\"mySchema\" (onChange)=\"value=$event.value\"\u003e\u003c/sf-form\u003e{{value | json}}';\n```\n\nThe `model` property allow two-way data binding:\n\n```\n\u003csf-form [schema]=\"mySchema\" [(model)]=\"value\"\u003e\u003c/sf-form\u003e{{value | json}}\n```\n\n### Widgets\n\nEach field can be displayed using a specific widget.\nTo declare the widget you want to use, add its `id` to the field's definition:\n\n```js\nmySchema = {\n  properties: {\n    email: {\n      type: \"string\",\n      description: \"email\",\n      format: \"email\",\n    },\n    password: {\n      type: \"string\",\n      description: \"Password\",\n      widget: \"password\", // == \"widget\": {\"id\": \"password\"}\n    },\n    rememberMe: {\n      type: \"boolean\",\n      default: false,\n      description: \"Remember me\",\n    },\n  },\n};\n```\n\nIf there is no widget declared in a given property's schema, its type is used as widget id and the [default registry](#default-widgets-registry) gives a default widget (see details below).\nFor instance, a string property will use the \"string\" widget.\nThe following JSON schema is equivalent with the above example:\n\n```js\nmySchema = {\n  properties: {\n    email: {\n      type: \"string\",\n      description: \"email\",\n      format: \"email\",\n      widget: \"string\",\n    },\n    password: {\n      type: \"string\",\n      description: \"Password\",\n      widget: \"password\", // == \"widget\": {\"id\": \"password\"}\n    },\n    rememberMe: {\n      type: \"boolean\",\n      default: false,\n      description: \"Remember me\",\n      widget: \"boolean\",\n    },\n  },\n};\n```\n\nSome widgets accept parameters as input, in such cases, it is possible to provide them in the schema directly within the `widget` property (here the [TinyMCE widget](https://github.com/fbessou/ng2sf-tinymce) ):\n\n```js\nmySchema = {\n  properties: {\n    pageContent: {\n      type: \"string\",\n      description: \"Page content\",\n      widget: {\n        id: \"richtext\",\n        plugins: \"textcolor colorpicker\",\n        toolbar: \"forecolor backcolor\",\n      },\n    },\n  },\n};\n```\n\n### Default widget's registry\n\nAvailable widgets are managed through a `WidgetRegistry`.\nThe default registry ([`DefaultWidgetRegistry`](./projects/schema-form/src/lib/defaultwidgets/defaultwidgetregistry.ts)) contains many widgets listed below, ordered by type:\n\n- **string**: string, search, tel, url, email, password, color, date, date-time, time, textarea, select, file, radio, richtext\n- **number**: number, integer, range\n- **integer**: integer, range\n- **boolean**: boolean, checkbox\n\nNote that the select and radio widgets rely on the `oneOf` property:\n\n```javascript\n\"operatingSystem\": {\n  \"type\": \"string\",\n  \"oneOf\": [\n    {\n      \"enum\": [\n        \"linux\"\n      ],\n      \"description\": \"GNU/Linux\"\n    },\n    {\n      \"enum\": [\n        \"osx\"\n      ],\n      \"description\": \"OSX\"\n    },\n    {\n      \"enum\": [\n        \"windows\"\n      ],\n      \"description\": \"Windows\"\n    },\n    {\n      \"enum\": [\n        \"other\"\n      ],\n      \"description\": \"Other\"\n    }\n  ],\n  \"default\": \"other\"\n}\n```\n\n### Actions and buttons\n\nEach schema can be extended by adding buttons after its widget.\n\n```js\n// app.component.ts\n@Component({\n  selector: \"minimal-app\",\n  // Bind the actions map to the the \"actions\" input\n  template: '\u003csf-form [schema]=\"mySchema\" [actions]=\"myActions\"\u003e\u003c/sf-form\u003e',\n})\nexport class AppComponent {\n  // The schema that will be used to generate a form\n  mySchema = {\n    properties: {\n      email: {\n        type: \"string\",\n        description: \"email\",\n        format: \"email\",\n      },\n      password: {\n        type: \"string\",\n        description: \"Password\",\n        buttons: [\n          {\n            id: \"reset\",\n            label: \"Reset\",\n          },\n        ],\n      },\n      rememberMe: {\n        type: \"boolean\",\n        default: false,\n        description: \"Remember me\",\n      },\n    },\n    required: [\"email\", \"password\", \"rememberMe\"],\n    buttons: [\n      {\n        id: \"alert\", // the id of the action callback\n        label: \"Alert !\", // the text inside the button\n      },\n    ],\n  };\n\n  // Declare a mapping between action ids and their event listener\n  myActions = {\n    alert: (property) =\u003e {\n      alert(JSON.stringify(property.value));\n    },\n    reset: (property) =\u003e {\n      property.reset();\n    },\n  };\n}\n```\n\n#### Render buttons\n\nYou may define you own widget to create buttons by\noverriding the default widget for action buttons\nor create completely customized button widgets.\n\n##### Override\n\nOverride the default action button widget\nin your `WidgetRegistry` implementation\nand register your own button widget.\n\n```js\nthis.register(\"button\", MyButtonWidgetComponent);\n```\n\n##### Custom\n\nDefine a custom button widget by\nsetting the property `button.widget` in the schema\n\n```json\n  \"password\": {\n    \"type\": \"string\",\n    \"description\": \"Password\",\n    \"buttons\": [\n      {\n        \"id\": \"reset\",\n        \"label\": \"Reset\"\n      },\n      {\n        \"id\": \"custom_b\",\n        \"label\": \"My custom button\",\n        \"widget\": \"my_custom_button\" // custom widget name for this button\n      }\n    ]\n  }\n```\n\nand then register it in your `WidgetRegistry` implementation\n\n```js\nthis.register(\"my_custom_button\", MyCustomButtonWidgetComponent);\n```\n\n##### Binding\n\nThe button widget will get provided the `button` object form the schema\nincluding the `button.action` from the action registry\nand the `formProperty` object.\n\nTo be fully AOT compatible\nthe custom button widget may then extend `ButtonWidget` or\nprovide the properties `button` and `formProperty` by it self.\n\n```js\nimport { Component } from \"@angular/core\";\nimport { ButtonWidget } from \"ngx-schema-form/dist/defaultwidgets\";\n\n@Component({\n  selector: \"sf-button-widget\",\n  templateUrl: \"custom-button.widget.html\",\n})\nexport class CustomWidgetComponent extends ButtonWidget {}\n```\n\n```js\n  @Component({\n    selector: 'sf-button-widget',\n    templateUrl: 'custom-button.widget.html'\n  })\n  export class CustomWidgetComponent {\n    public button\n    public formProperty\n  }\n```\n\n### Advanced validation\n\nJSON schema provides validation against a static schema but its often necessary to provide other validation rules.\nThe Form component accepts a `validators` input bound to a map between a field id and a validation function.\nThe validation function takes three arguments: the value of the field, the property corresponding to it and the form object.\n\nIn the following example we create a simple registration form.\nThe user have to enter his password twice.\nTo perform this check we create a custom validator:\n\n```js\n@Component({\n  selector: \"minimal-app\",\n  // Bind the validator map to the the \"validators\" input\n  template:\n    '\u003csf-form [schema]=\"mySchema\" [validators]=\"myValidators\"\u003e\u003c/sf-form\u003e',\n})\nexport class AppComponent {\n  mySchema = {\n    properties: {\n      email: {\n        type: \"string\",\n        description: \"email\",\n        format: \"email\",\n      },\n      password: {\n        type: \"string\",\n        description: \"Password\",\n      },\n      passwordCheck: {\n        type: \"string\",\n        description: \"Password (verification)\",\n      },\n    },\n    required: [\"email\", \"password\", \"passwordCheck\"],\n  };\n\n  // Declare a mapping between action ids and their implementations\n  myValidators = {\n    \"/passwordCheck\": (value, property, form) =\u003e {\n      const passwordProperty = formProperty.findRoot().getProperty(\"password\");\n      if (\n        passwordProperty.value !== undefined \u0026\u0026\n        property.valid \u0026\u0026\n        value !== passwordProperty.value\n      ) {\n        return { passwordCheck: { expectedValue: \"same as 'password'\" } };\n      }\n      return null;\n    },\n  };\n}\n```\n\n### Custom Bindings\n\nSome form field may require a reaction to other forms fields when getting some input.\nThe Form component accepts a `bindings` input bound to a map of field paths mapped to event and binding functions.  \nThe binding function takes two arguments: the native event, and the property corresponding to it.\n\nThe following example creates a form where you will fill in some data for a family.\nWhen you type in the name of the parent (first person) the name of the children will be kept updated.\n\n```js\n@Component({\n  selector: \"minimal-app\",\n  // Bind the bindings map to the the \"bindings\" input\n  template:\n    '\u003csf-form [schema]=\"mySchema\" [bindings]=\"myFieldBindings\"\u003e\u003c/sf-form\u003e',\n})\nexport class AppComponent {\n  mySchema = {\n    type: \"object\",\n    title: \"Example with custom bindings.\",\n    description:\n      \"Type a family name to see how the name gets synchronized with the children.\",\n    properties: {\n      name: {\n        type: \"string\",\n        title: \"Surname\",\n      },\n      forename: {\n        type: \"string\",\n        title: \"Forename\",\n      },\n      children: {\n        type: \"array\",\n        title: \"Family\",\n        items: {\n          type: \"object\",\n          title: \"Children\",\n          properties: {\n            name: {\n              type: \"string\",\n              title: \"Surname\",\n            },\n            forename: {\n              type: \"string\",\n              title: \"forename\",\n            },\n            age: {\n              type: \"number\",\n              title: \"age\",\n            },\n          },\n        },\n      },\n    },\n  };\n\n  // Declare a mapping between field and event-id\n  myFieldBindings = {\n    \"/name\": [\n      {\n        input: (event, formProperty: FormProperty) =\u003e {\n          const parent: PropertyGroup = formProperty.findRoot();\n\n          /**\n           * Set the input value for the children\n           */\n          const child1: FormProperty = parent.getProperty(\"children/0/name\");\n\n          child1.setValue(formProperty.value, false);\n\n          const child2: FormProperty = parent.getProperty(\"children/1/name\");\n          child2.setValue(event.target.value, false);\n\n          /**\n           * Get the input value for all the children\n           */\n          for (const objectProperty of parent.getProperty(\"children\")\n            .properties) {\n            console.log(\n              \"Value for child \",\n              objectProperty,\n              objectProperty.properties[\"name\"].value\n            );\n          }\n        },\n      },\n    ],\n  };\n}\n```\n\n### Conditional fields\n\nIt is possible to make the presence of a field depends on another field's value.  \nTo achieve this you just have to add a `visibleIf` property to a field's definition.\n\n**Value**  \nThe value to match is set as array item.  \nSetting multiple items will make the visiblity condition `true` if one of the values matches.  \nIf it is required to match all values head over to the section `visibleIf` with `allOf` condition.\n\n**$ANY$**  \nAdding the value `$ANY$` to the array of conditional values, will make the field visible for any value inserted.\n\n```js\n@Component({\n  selector: \"minimal-app\",\n  template: '\u003csf-form [schema]=\"mySchema\"\u003e\u003c/sf-form\u003e',\n})\nexport class AppComponent {\n  mySchema = {\n    properties: {\n      name: {\n        type: \"string\",\n        description: \"Username\",\n      },\n      comment: {\n        type: \"string\",\n        description: \"Comment\",\n      },\n      registerNewsletter: {\n        type: \"boolean\",\n        description: \"I want to receive the newsletter\",\n        default: false,\n        visibleIf: {\n          comment: [\"$ANY$\"],\n        },\n      },\n      registerEmail: {\n        type: \"string\",\n        description: \"Email\",\n        format: \"email\",\n        // Declare that this field must be displayed only if registerNewsletter is true\n        visibleIf: {\n          registerNewsletter: [true],\n        },\n      },\n    },\n    required: [\"name\", \"comment\", \"registerToNewsletter\"],\n  };\n}\n```\n\n**$EMPTY$**  \nAssigning an empty Object to 'visibleIf' is interpreted as _visibleIf_ nothing, thereby the widget is hidden and not present in model.\n\n```js\nmySchema = {\n  properties: {\n    hidden: {\n      type: \"boolean\",\n      visibleIf: {},\n    },\n  },\n};\n```\n\n`visibleIf` may also declare conditional binding by using `oneOf` or `allOf` properties.\nWhere `oneOf` is handled as `OR` and `allOf` is handled as `AND`.\n\n```\n  \"visibleIf\": {\n        \"allOf\": [\n          {\n            \"forename\": [\n              \"$ANY$\"\n            ]\n          },\n          {\n            \"name\": [\n              \"$ANY$\"\n            ]\n          }\n        ]\n      }\n```\n\nThe `oneOf` a is prioritized before the `allOf` and both are prioritized before the\nproperty binding.\n\nChaining of `oneOf` and `allOf` is possible like in the example below:\n```\n\"visibleIf\": {\n  \"allOf\": [\n    {\n      \"oneOf\": [{ \"/demo/visibleIfBinding1/status1a\": [\"Pass\"] }, { \"/demo/visibleIfBinding1/status1b\": [\"Pass\"] }]\n    },\n    {\n      \"oneOf\": [{ \"/demo/visibleIfBinding1/status1c\": [\"Pass\"] }, { \"/demo/visibleIfBinding1/status1d\": [\"Pass\"] }]\n    }\n  ]\n}\n```\n\n_`oneOf` and `allOf` are reserved keywords and not suitable as property names_\n\n**Arrays**\n\nTo address array items or not yet existing properties the `visibleIf`\ncondition path may contain wildcard `*`.\n\ne.g\n\n```\n  \"visibleIf\": {\n        \"oneOf\": [\n          {\n            \"/person/*/age\": [\n              \"18\"\n            ]\n          }\n        ]\n      }\n```\n\nTo address a specific item the `visibleIf`\ncondition path should contain the index position.\n\ne.g\n\n```\n  \"visibleIf\": {\n        \"oneOf\": [\n          {\n            \"/person/1/age\": [\n              \"18\"\n            ]\n          }\n        ]\n      }\n```\n\n**Expressions**\n\nExpressions allow a more complex `visibleIf` condition related to the involded fields.  \nTo use an expression the value of the item  \nin the conditional array must start with `$EXP$`.  \nWhen processing the expression a context is available containing  \na `source` and a `target` object.  \nWhere `source` is the `FormProperty` that has the `visibleIf` condition defined  \nand `target` is the `FormProperty` that has been defined by the `path`.\n\n```\n  \"myField\" : { // SOURCE\n    \"visibleIf\": {\n          \"oneOf\": [\n            {\n              \"/person/1/age\": // TARGET\n              [\n                \"$EXP$ target.value \u003c 18\"\n              ]\n            }\n          ]\n        }\n   }\n```\n\n#### Hidden fields\n\nWhen a field has been made invisible by the condition `visibleIf`\nthen the property of the invisible field will be missing in the result model.\n\nIf there is need to submit default values that are not visible for the form\nthe `widget.id` `hidden` might be the better choice\n\n```js\n  mySchema = {\n    \"properties\": {\n      \"hiddenInput\": {\n        \"type\": \"boolean\",\n        \"widget\": \"hidden\",\n        \"default\": true\n      },\n      \"lastName\": {\n        \"type\": \"string\",\n        ...\n      }\n    }\n  }\n```\n\nso the value of the hidden field will be bound to the output model\n\n```js\n  {\n    \"hiddenInput\": true,\n    \"lastName\": \"Doe\",\n    ...\n  }\n```\n\n### Fields presentation and ordering\n\nAs a JSON object is an unordered collection you can't be sure your fields will be correctly ordered when the form is built.\nThe `order` and `fieldsets` entries of the schema are here to organize your fields.\n\n#### Ordering\n\nThe `order` entry is an array listing all the fields ids in the order they must appear in the form:\n\n```js\n{\n  \"properties\": {\n    \"firstName\": {\"type\": \"string\",\"description\": \"First name\"},\n    \"lastName\": {\"type\": \"string\",\"description\": \"Last name\"},\n    \"email\": {\"type\": \"string\",\"description\": \"Email\"}\n  },\n  \"order\": [\"firstName\", \"lastName\", \"email\"]\n}\n```\n\n#### Fieldsets\n\nWith the `fieldsets` property, you can describe the different parts of the form and the fields they contain:\n\n```js\n{\n  \"properties\": {\n    \"firstName\": {\n      \"type\": \"string\",\n      \"description\": \"First name\"\n    },\n    \"lastName\": {\n      \"type\": \"string\",\n      \"description\": \"Last name\"\n    },\n    \"email\": {\n      \"type\": \"string\",\n      \"description\": \"Email\"\n    },\n    \"notificationsFrequency\": {\n      \"type\": \"string\",\n      \"description\": \"Notifications frequency\",\n      \"widget\": \"select\",\n      \"oneOf\": [\n        {\n          \"description\": \"Daily\",\n          \"enum\": [\n            \"daily\"\n          ]\n        },\n        {\n          \"description\": \"Weekly\",\n          \"enum\": [\n            \"weekly\"\n          ]\n        },\n        {\n          \"description\": \"Monthly\",\n          \"enum\": [\n            \"monthly\"\n          ]\n        }\n      ],\n      \"default\": \"daily\"\n    }\n  },\n  \"fieldsets\": [\n    {\n      \"title\": \"Personal information\",\n      \"fields\": [\n        \"firstName\",\n        \"lastName\",\n        \"email\"\n      ]\n    },\n    {\n      \"title\": \"Account settings\",\n      \"fields\": [\n        \"notificationsFrequency\"\n      ]\n    }\n  ]\n}\n```\n\nThe `title` entry of each fieldset is optional.\n\n## Fixing the schema or model before rendering\n\nSometimes your schema (or model) is provided by a backend you cannot control.\nIf it is not formatted the way Angular 2 Schema Form expects or if some elements are missing (for instance the fieldsets, some widgets, etc.), you can fix it very easily in your component:\n\n```javascript\n@Component({\n  selector: 'plone-view-edit',\n  template: '\u003csf-form [schema]=\"schema\" [model]=\"model\" [actions]=\"actions\"\u003e\u003c/sf-form\u003e'\n})\nexport class MyComponent {\n  private schema: any = {\n    'properties': {}\n  };\n  private actions: any = {};\n  private model: any = {};\n\n  constructor(private http: Http) { }\n\n  ngOnInit() {\n    this.http.get('http://mybackend/schema').subscribe(res =\u003e {\n      let schema = res.json();\n\n      // FIXES\n      // the \"description\" field must be rendered with tinymce\n      schema.properties.description.widget = 'tinymce'\n\n      // the \"publication\" field is required\n      schema.required = ['publication'];\n\n      this.schema = schema;\n    });\n  }\n}\n```\n\n## Creating a custom widget\n\nNgx schema form allows you to create your own widget.\n\nNote: Currently this feature is not completely defined and the API might change.\n\nYou need to derivate the widget you want to customize:\n\n```javascript\n@Component({\n  selector: \"mdl-sf-string-widget\",\n  templateUrl: \"./string.widget.html\",\n})\nexport class MyStringWidget extends StringWidget {}\n```\n\nYou need to provide its html template (let's imagine we want to use the Material Design text field):\n\n```html\n\u003cmdl-textfield\n  [label]=\"schema.description\"\n  type=\"string\"\n  floating-label\n  [name]=\"name\"\n  [attr.readonly]=\"schema.readOnly?true:null\"\n  [attr.id]=\"id\"\n  [attr.disabled]=\"schema.readOnly?true:null\"\n  [formControl]=\"control\"\n\u003e\u003c/mdl-textfield\u003e\n```\n\nAnd you need to declare it in a custom registry:\n\n```javascript\nimport { MyStringWidget } from \"./mystring\";\n\nexport class MyWidgetRegistry extends DefaultWidgetRegistry {\n  constructor() {\n    super();\n\n    this.register(\"string\", MyStringWidget);\n  }\n}\n```\n\nAnd, in your module, you need to:\n\n- declare your widget component (like any regular component),\n- declare it as an entry components (it means it can be instanciated dynamically),\n- and provide your registry.\n\n```javascript\ndeclarations: [MyStringWidget],\nentryComponents: [MyStringWidget],\nproviders: [{provide: WidgetRegistry, useClass: MyWidgetRegistry}],\n```\n\nNote: you will also need to import `ReactiveFormsModule` if you want to be able to use form control:\n\n```javascript\nimport { ReactiveFormsModule } from '@angular/forms';\n...\n@NgModule({\n  ...\n  imports: [\n    ...\n    ReactiveFormsModule,\n  ]\n})\n```\n\n## Create form from html instead of json schema\n\nNgx schema form allows you to create forms from angular html templates too.\nFor this you only need to import `TemplateSchemaModule` to your app, and use the\ndirective `templateSchema` on sf-form.\n\nThe followin html will generate the same form as the json schema in getting started section.\n\n```html\n\u003csf-form [(ngModel)]=\"model\" templateSchema\u003e\n  \u003csf-field name=\"email\" format=\"email\" [required]=\"true\"\u003e Email \u003c/sf-field\u003e\n  \u003csf-field name=\"password\" widget=\"password\" [required]=\"true\"\u003e\n    Password\n  \u003c/sf-field\u003e\n  \u003csf-field name=\"rememberMe\" type=\"boolean\"\u003e Remember Me \u003c/sf-field\u003e\n\u003c/sf-form\u003e\n```\n\nFor more details see example app.\n\n## Development and build\n\nTo work on this package:\n\n```bash\nnpm install\n```\n\nThen you can build:\n\n```bash\nnpm run build:lib\n```\n\nIf you want to work with the demo:\n\n```bash\nnpm install -g @angular/cli\nnpm install\nng build schema-form\nnpm start\n```\n\n## Building the API documentation\n\nYou can build an HTML version of the API documentation by running the following command:\n\n```bash\nnpm run typedoc\n```\n\nThe api is then available in the \"doc\" directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillotinaweb%2Fngx-schema-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguillotinaweb%2Fngx-schema-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillotinaweb%2Fngx-schema-form/lists"}