{"id":19657725,"url":"https://github.com/esss/ng-xform","last_synced_at":"2025-04-28T19:32:24.474Z","repository":{"id":57112070,"uuid":"118787875","full_name":"ESSS/ng-xform","owner":"ESSS","description":null,"archived":false,"fork":false,"pushed_at":"2022-11-30T17:06:10.000Z","size":5560,"stargazers_count":17,"open_issues_count":1,"forks_count":1,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-10-28T17:12:32.938Z","etag":null,"topics":["angular6","forms"],"latest_commit_sha":null,"homepage":"https://esss.github.io/ng-xform/home","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/ESSS.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}},"created_at":"2018-01-24T16:01:25.000Z","updated_at":"2024-06-18T16:09:28.000Z","dependencies_parsed_at":"2023-01-22T01:48:25.330Z","dependency_job_id":null,"html_url":"https://github.com/ESSS/ng-xform","commit_stats":null,"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESSS%2Fng-xform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESSS%2Fng-xform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESSS%2Fng-xform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESSS%2Fng-xform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ESSS","download_url":"https://codeload.github.com/ESSS/ng-xform/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224129255,"owners_count":17260589,"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":["angular6","forms"],"created_at":"2024-11-11T15:33:23.668Z","updated_at":"2024-11-11T15:33:24.700Z","avatar_url":"https://github.com/ESSS.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ng-xform - Angular library built using ngx-library yeoman generator.\n\n[![npm version](https://badge.fury.io/js/%40esss%2Fng-xform.svg)](https://badge.fury.io/js/%40esss%2Fng-xform)\n[![Build Status](https://github.com/ESSS/ng-xform/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/ESSS/ng-xform/actions)\n[![Coverage Status](https://coveralls.io/repos/github/ESSS/ng-xform/badge.svg?branch=master)](https://coveralls.io/github/ESSS/ng-xform?branch=master)\n[![dependencies Status](https://david-dm.org/esss/ng-xform/status.svg)](https://david-dm.org/esss/ng-xform)\n[![devDependencies Status](https://david-dm.org/esss/ng-xform/dev-status.svg)](https://david-dm.org/esss/ng-xform?type=dev)\n\n## Demo\n\nView all the directives in action at [Demo](https://esss.github.io/ng-xform) and [Demo source code](https://github.com/ESSS/ng-xform/blob/master/demo/src/app/home/home.component.ts)\n\n## Dependencies\n* [Angular](https://angular.io) (*requires* Angular 6, tested with 6.1.0)\n\n## Installation\nInstall above dependencies via *npm*. \n```shell\nnpm i --save @ng-select/ng-select@2.3.5 ngx-bootstrap@3.0.1 mathjs@3.20.2\n```\n\nNow install `@esss/ng-xform` via:\n```shell\nnpm i --save @esss/ng-xform\n```\n\nYou will need to import styles. Example: 'src/styles.scss'\n```css\n@import 'bootstrap/dist/css/bootstrap.min.css';\n@import 'ngx-bootstrap/datepicker/bs-datepicker.css';\n@import \"@ng-select/ng-select/themes/default.theme.css\";\n```\n\nSetup the MeasureComponent adding the js file on .angular-cli.json \n```json\n\"scripts\": [\n  \"../node_modules/mathjs/dist/math.js\"\n]\n```\n\n---\n##### SystemJS\n\u003e**Note**:If you are using `SystemJS`, you should adjust your configuration to point to the UMD bundle.\nIn your systemjs config file, `map` needs to tell the System loader where to look for `@esss/ng-xform`:\n```js\nmap: {\n  '@esss/ng-xform': 'node_modules/@esss/ng-xform/bundles/ng-xform.umd.js',\n}\n```\n---\n\nOnce installed you need to import the main module:\n```js\nimport { NgXformModule } from '@esss/ng-xform';\n```\nThe only remaining part is to list the imported module in your application module. The exact method will be slightly\ndifferent for the root (top-level) module for which you should end up with the code similar to (notice ` NgXformModule`):\n```js\nimport { NgXformModule } from '@esss/ng-xform';\n\n@NgModule({\n  declarations: [AppComponent, ...],\n  imports: [NgXformModule, ...],  \n  bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n```\n\nOther modules in your application can simply import ` NgXformModule `:\n\n```js\nimport { NgXformModule } from '@esss/ng-xform';\n\n@NgModule({\n  declarations: [OtherComponent, ...],\n  imports: [NgXformModule, ...], \n})\nexport class OtherModule {\n}\n```\n\n## Usage\nTemplate:\n```html\n \u003cng-xform [horizontalForm]=\"horizontal\" [labelWidth]=\"labelWidth\" [fields]=\"fields\" \u003e\u003c/ng-xform\u003e\n```\nComponent:\n```ts\nexport class HomeComponent implements OnInit, OnDestroy {\n\n  @ViewChild(NgXformEditSaveComponent) xformComponent: NgXformEditSaveComponent;\n  @ViewChild('customField') customFieldTmpl: TemplateRef\u003cany\u003e;\n\n  private colors: any[] = [\n    { id: 0, name: 'other' },\n    { id: 1, name: 'blue' },\n    { id: 2, name: 'yellow' },\n    { id: 3, name: 'white' },\n    { id: 4, name: 'black' },\n    { id: 5, name: 'orange' },\n    { id: 6, name: 'purple' }\n  ];\n\n  public onchangefn = new Subject\u003cstring\u003e();\n\n  public fields: DynamicField[];\n  public horizontal = false;\n  public labelWidth = 2;\n  public model: any;\n  public outputhelper = {'A': 1, 'B': 2, 'C': 3};\n  public subscriptions: Subscription[] = [];\n\n  constructor(private titleService: Title, private http: HttpClient) { }\n\n  ngOnInit() {\n    const minDate = new Date();\n    const maxDate = new Date();\n\n    this.subscriptions.push(this.onchangefn.asObservable().subscribe(\n      (value: any) =\u003e  this.xformComponent.setValue({'outputopt': this.outputhelper[value]})\n    ));\n\n    minDate.setDate(minDate.getDate() - 3);\n    maxDate.setDate(maxDate.getDate() + 3);\n    this.titleService.setTitle('Home | @esss/ng-xform');\n    this.fields = [\n      new TextField({\n        key: 'name',\n        label: 'Name',\n        validators: [\n          Validators.minLength(3)\n        ]\n      }),\n      new TextField({\n        key: 'email',\n        label: 'E-mail',\n        validators: [\n          Validators.required,\n          Validators.email\n        ]\n      }),\n      new SelectField({\n        key: 'color_ro',\n        label: 'Color read-only',\n        readOnly: true,\n        searchable: true,\n        options: this.colors,\n        optionLabelKey: 'name',\n      }),\n      new SelectField({\n        key: 'color',\n        label: 'Color',\n        searchable: true,\n        options: this.colors,\n        addNewOption: true,\n        addNewOptionText: 'Add Color',\n        optionLabelKey: 'name',\n      }),\n      new TextField({\n        key: 'other',\n        label: 'Other color',\n        visibilityFn: (value: any) =\u003e value.color \u0026\u0026 value.color.id === 0\n      }),\n      new NestedFormGroup({\n        key: 'address',\n        fields: [\n          new SelectField({\n            key: 'country',\n            label: 'Country',\n            searchHandler: this.observableSource.bind(this),\n            searchByValueKeyHandler: this.observableSourceByPlaceId.bind(this),\n            searchOnFocus: true,\n            searchable: true,\n            optionLabelKey: 'name',\n            optionValueKey: 'alpha3Code',\n            validators: [\n              Validators.required\n            ]\n          })\n        ]\n      }),\n      new SelectField({\n        key: 'type',\n        label: 'Type',\n        options: ['a', 'b'],\n        validators: [\n          Validators.required\n        ]\n      }),\n      new SelectField({\n        key: 'type_tags',\n        label: 'Type tags',\n        options: [{id: 1, description: 'A'}, {id: 2, description: 'B'}, {id: 3, description: 'C'}],\n        optionLabelKey: 'description',\n        optionValueKey: 'id',\n        multiple: true\n      }),\n      new MeasureField({\n        key: 'length',\n        label: 'Length',\n        modelUnit: 'mm',\n        viewUnit: of('m').pipe(delay(200)),\n        availableUnits: of(['m', 'cm', 'mm']).pipe(delay(200))\n      }),\n      new MeasureField({\n        key: 'width',\n        label: 'Width',\n        modelUnit: 'inch',\n        viewUnit: of('inch').pipe(delay(200)),\n        availableUnits: of(['inch', 'ft']).pipe(delay(200))\n      }),\n      new SelectField({\n        key: 'opt',\n        label: 'Select an option',\n        options: [{id: 'A', description: 'Option A'}, {id: 'B', description: 'Option B'}, {id: 'C', description: 'Option C'}],\n        optionLabelKey: 'description',\n        optionValueKey: 'id',\n        onChangeFn: (value: string) =\u003e {\n          this.onchangefn.next(value);\n        }\n      }),\n      new TextField({\n        key: 'outputopt',\n        label: 'Output of option',\n        readOnly: true,\n      }),\n      new CheckboxField({\n        key: 'news',\n        label: 'News'\n      }),\n      new RadioGroupField({\n        key: 'gender',\n        label: 'Gender',\n        options: of([{id: 1, label: 'male'}, {id: 2, label: 'female'}]).pipe(delay(2000)),\n        optionValueKey: 'id',\n        optionLabelKey: 'label'\n      }),\n      new MultilineField({\n        key: 'comment',\n        label: 'Comment',\n        rows: 4\n      }),\n      new DateField({\n        key: 'birth',\n        label: 'Date of birth',\n        theme: 'blue',\n        minDate: minDate,\n        maxDate: maxDate,\n        showWeekNumbers: true\n      }),\n      new DateRangeField({\n        key: 'range',\n        label: 'Date range',\n        theme: 'blue'\n      }),\n      new CustomField({\n        key: 'custom_amount',\n        label: 'Custom Field Amount',\n        tmpl: this.customFieldTmpl\n      }),\n    ];\n  }\n\n  ngOnDestroy() {\n    this.subscriptions.forEach(sub =\u003e sub.unsubscribe());\n  }\n\n  public onSubmit(values: object) {\n    this.model = values;\n  }\n\n  populate() {\n    this.xformComponent.setValue({\n      name: 'Customer',\n      email: 'customer@mail.com',\n      type_tags: [2],\n      type: 'b',\n      color: { id: 3, name: 'white' },\n      color_ro: { id: 3, name: 'white' },\n      address: {\n        street: 'ChIJn7h-4b9JJ5URGCq6n0zj1tM'\n      },\n      gender: 1,\n      length: { value: 2, unit: 'm'},\n      width: { value: 3, unit: 'ft'},\n      opt: 'A',\n      news: true,\n      comment: 'Mussum Ipsum, cacilds vidis litro abertis. Mauris nec dolor in eros commodo tempor. Aenean aliquam molestie leo, vitae ' +\n      'iaculis nisl. Quem num gosta di mé, boa gentis num é. Tá deprimidis, eu conheço uma cachacis que pode alegrar sua vidis. Em pé ' +\n      'sem cair, deitado sem dormir, sentado sem cochilar e fazendo pose. Leite de capivaris, leite de mula manquis sem cabeça. Praesent ' +\n      'vel viverra nisi. Mauris aliquet nunc non turpis scelerisque, eget. Casamentiss faiz malandris se pirulitá. Sapien in monti ' +\n      'palavris qui num significa nadis i pareci latim.',\n      birth: new Date(),\n      range: [\n        '2018-09-06T03:00:00.000Z',\n        '2018-10-08T03:00:00.000Z'\n      ],\n      custom_amount: 456\n    });\n  }\n\n  public observableSource(keyword: any): Observable\u003cany[]\u003e {\n    const url = `https://restcountries.eu/rest/v2/name/${keyword}`;\n    if (keyword) {\n      return this.http.get(url)\n        .pipe(\n          map((res) =\u003e res as any[])\n        );\n    } else {\n      return of([]);\n    }\n  }\n\n  public observableSourceByPlaceId(keyword: any): Observable\u003cany\u003e {\n    return of({\n      'alpha3Code': 'BRA',\n      'name': 'Brazil'\n    }).pipe(delay(300));\n  }\n}\n```\n### Custom Field\n\nIt's possible to create your own field template and set it on dynamic field list through CustomField\n\nExample:\n`my-component.html`\n```html\n\u003cng-template #customField let-customControl=\"control\" let-isEditing=\"isEditing\"\u003e\n  \u003cdiv class=\"input-group\"\u003e\n    \u003cdiv class=\"input-group-addon\"\u003e$\u003c/div\u003e\n    \u003cinput type=\"number\"\n      [formControl]=\"customControl\"\n      [attr.disabled]=\"!isEditing || null\" \n      class=\"form-control\"\n      style=\"text-align:right\" \n      id=\"exampleInputAmount\" \n      placeholder=\"Amount\" /\u003e\n    \u003cdiv class=\"input-group-addon\"\u003e.00\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/ng-template\u003e\n```\n\n`my-component.ts`\n```ts\n\n  @ViewChild('customField') customFieldTmpl: TemplateRef\u003cany\u003e;\n  public fields: DynamicField[];\n  ...\n  ngOnInit() {\n    this.fields = [\n      new CustomField({\n        key: 'custom_amount',\n        label: 'Custom Field Amount',\n        tmpl: this.customFieldTmpl\n      }),\n    ];\n  }\n``` \n\n### Typed key validation\n\nNow it is possible to define a type that will be used to validate the key field values\n\nExample:\n```ts\n\nclass Address {\n  street: string;\n  city: string;\n}\n\nclass User {\n  name: string;\n  email: string;\n  address: Address;\n}\n\nexport class UserComponent {\n\n  public fields: DynamicField[];\n\n  constructor() {\n\n    this.fields = [\n      new TextField\u003cUser\u003e({\n        key: 'name',\n        label: 'Name',\n        validators: [\n          Validators.minLength(3)\n        ]\n      }),\n      new TextField\u003cUser\u003e({\n        key: 'email',\n        label: 'E-mail',\n        validators: [\n          Validators.required,\n          Validators.email\n        ]\n      }),\n      new NestedFormGroup\u003cUser\u003e({\n        key: 'address',\n        fields: [\n          new TextField\u003cAddress\u003e({\n            key: 'street',\n            label: 'Street',\n          }),\n          new TextField\u003cAddress\u003e({\n            key: 'city',\n            label: 'City',\n          }),\n        ]\n      })\n    ];\n  }\n}\n```\n\nIn the example, the ```TextField``` is created specialized whit the ```User``` class\n```ts\nnew TextField\u003cUser\u003e({\n``` \nthe TextField ```key``` attribute will accept only keys of the class User (i.e. 'name', 'email', 'address'), and show and error if any other value is provided.\n\n### On change function\nYou can add a parameter ```onChangeFn``` on your ```DynamicField``` fields. This parameter receives a \nanonymous function, just like in the following example:\n\n```ts\nnew TextField({\n  key: 'phrase',\n  label: 'Write a phrase',\n  onChangeFn: (value: string) =\u003e {\n    // push new typed value to a subject\n    this.onchangefnSubject.next(value);\n  }\n}),\n```\nThis parameter can be used to execute async functions that depends on user input or push values of \na field to a ```Subject()``` just like is shown above. \n\n\n### Locales\nDatepickerField can use different locales. \n\nIt's possible to change a locale by calling use method of BsLocaleService, list of available locales is in dropdown below.\n\nTo use a different locale, you have to import it from ngx-bootstrap/chronos first, then define it in your @NgModule using function defineLocale\n\nExample: \n\n```ts\nimport { defineLocale, LocaleData } from 'ngx-bootstrap/chronos';\nimport { ptBrLocale } from 'ngx-bootstrap/locale';\ndefineLocale(ptBrLocale.abbr, ptBrLocale);\n\n...\n\nexport class AppModule {\n\n  constructor(bsLocaleService: BsLocaleService) {\n    // aplly locale\n    bsLocaleService.use(ptBrLocale.abbr);\n  }\n}\n```\n\n[Demo source code](https://github.com/ESSS/ng-xform/blob/master/demo/src/app/app.module.ts) load locales.\n\n## Development\n\nAfter cloning of this repository will be necessary run once ```npm run setup```, so will be able to run ```npm run demo``` to start the demo locally\n\nFor more information view common development activities on https://github.com/tinesoft/generator-ngx-library#development\n\n## License\n\nCopyright (c) 2018 ESSS. Licensed under the MIT License (MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesss%2Fng-xform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fesss%2Fng-xform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesss%2Fng-xform/lists"}