dynaform.service.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* *********************************************************************************************************************
  2. * Dynaform Service, exposing 10 public methods
  3. * *********************************************************************************************************************
  4. *
  5. * BUILD
  6. * -----
  7. * This is the main method you'll use to build forms from models and metadata:
  8. *
  9. * build(model, meta = {}, createFromMeta = false)
  10. *
  11. * Takes a model and (lazy)metadata and returns an object containing a FormGroup and Modeled MetaData :
  12. * {
  13. * form: FormGroup,
  14. * meta: ModeledMetaData
  15. * }
  16. *
  17. * meta is optional, and if not supplied all the model fields will become Text inputs in the FormGroup,
  18. * with their labels set to the un-camel-cased property name
  19. *
  20. * createFromMeta is optional.
  21. * If true it will create new fields in the FormGroup even when they don't already exist in the model,
  22. * but exist in the metadata. This is NOT the default behaviour, except when an empty model is supplied.
  23. * i.e. It defaults to false, except when model == {}
  24. *
  25. * Usage
  26. * -----
  27. *
  28. * build(model) - build everything from the model
  29. * build({}, meta) - build everything from the metadata
  30. * build(model, meta) - build by combining the model with metadata, lazyily (not every model field needs metadata, as sensible defaults)
  31. * build(model, meta, true) - build by combining model with metadata, creating new fields from metadata points that don't occur in the model
  32. *
  33. *
  34. * REGISTER
  35. * --------
  36. * Registers callbacks attached to the form (e.g. to buttons), identified by strings.
  37. *
  38. * register({
  39. * 'SAYHELLO': () => { alert('HELLO') },
  40. * 'SEARCH': execSearch,
  41. * 'NEW': addNew,
  42. * }, varToBind);
  43. *
  44. * If varToBind is supplied it is bound as 'this' to the functions.
  45. * Typically you'd supply the component class instance, so that 'this' used in callbacks refers to the host component.
  46. *
  47. *
  48. * LOWER-LEVEL METHODS
  49. * -------------------
  50. *
  51. * autoBuildFormGroupAndMeta(model, meta, createFromMeta) - synonym for build
  52. * autoBuildModeledMeta(model, meta, createFromMeta) - takes a model and (lazy)metadata and returns expanded metadata
  53. *
  54. * buildFormGroup(metadata) - builds FormGroups from modelled metdata, recursively if necessary
  55. * buildFieldSpecificMeta(metadata) - use field metadta models to fill out metadata
  56. * combineModelWithMeta(model, extraMeta) - automatically generated metadata for model then combines extra metadata
  57. * combineExtraMeta(metadata, extraMeta) - combine extra metadata into metatdata, lazyly and recursively
  58. * autoMeta(model) - generate basic metadata from a raw or mapped model, recursively if necessary
  59. *
  60. *
  61. * NOTES
  62. * -----
  63. * This class acts as an injectable wraper around the exports of _formdata-utils.ts,
  64. * as well as creating a buildFormGroup function using the injected FormBuilder singleton
  65. *
  66. *
  67. * EXAMPLES
  68. * --------
  69. *
  70. * TO ADD ...
  71. *
  72. */
  73. import { Injectable, ComponentRef } from '@angular/core';
  74. import { FormBuilder, FormGroup } from '@angular/forms';
  75. import {
  76. autoMeta, combineModelWithMeta, combineExtraMeta,
  77. buildFieldSpecificMeta, buildFormGroupFunctionFactory
  78. } from './_formdata-utils';
  79. export interface FormAndMeta {
  80. form: FormGroup;
  81. meta: StringMap;
  82. }
  83. export interface Callbacks {
  84. [index: string]: () => void
  85. }
  86. @Injectable()
  87. export class DynaformService {
  88. public buildFormGroup: (meta) => FormGroup;
  89. private callbacks: Callbacks = {};
  90. constructor(private fb: FormBuilder) {
  91. this.buildFormGroup = buildFormGroupFunctionFactory(fb);
  92. }
  93. build(model: StringMap, meta = {}, createFromMeta = false): FormAndMeta {
  94. // Short name for autoBuildFormGroupAndMeta
  95. return this.autoBuildFormGroupAndMeta(model, meta, createFromMeta);
  96. }
  97. register(callbacks: Callbacks, cref: ComponentRef<any>['instance']) {
  98. // Bind the component instance to the callback, so that 'this' has the context of the component
  99. if (cref) {
  100. Object.entries(callbacks).forEach(([key, fn]) => this.callbacks[key] = fn.bind(cref));
  101. }
  102. }
  103. call(fnId: string) {
  104. console.log('Dynaform Service', fnId);
  105. // Handle callback events
  106. try {
  107. this.callbacks[fnId]();
  108. }
  109. catch(e) {
  110. console.error('Dynaform has no registered callback for', fnId);
  111. console.error(e);
  112. }
  113. }
  114. // -----------------------------------------------------------------------------------------------------------------
  115. // Convenience methods combining several steps
  116. autoBuildFormGroupAndMeta(model: StringMap, meta = {}, createFromMeta = false): FormAndMeta {
  117. if (Object.keys(model).length === 0) {
  118. createFromMeta = true;
  119. }
  120. const modelWithMeta = this.autoBuildModeledMeta(model, meta, createFromMeta);
  121. return {
  122. form: this.buildFormGroup(modelWithMeta),
  123. meta: modelWithMeta
  124. };
  125. }
  126. autoBuildModeledMeta(model: StringMap, meta = {}, createFromMeta = false) {
  127. const modelWithMeta = this.combineModelWithMeta(model, meta, createFromMeta);
  128. return this.buildFieldSpecificMeta(modelWithMeta);
  129. }
  130. // -----------------------------------------------------------------------------------------------------------------
  131. // Build field-type-specific metadata using the form field models (see dynaform/models)
  132. buildFieldSpecificMeta(meta) {
  133. return buildFieldSpecificMeta(meta);
  134. }
  135. // -----------------------------------------------------------------------------------------------------------------
  136. // Lower-level methods
  137. combineModelWithMeta(model: StringMap, meta, createFromMeta = false) {
  138. return combineModelWithMeta(model, meta, createFromMeta);
  139. }
  140. combineExtraMeta(meta, extraMeta, createFromExtra = false) {
  141. return combineExtraMeta(meta, extraMeta, createFromExtra);
  142. }
  143. autoMeta(model) {
  144. return autoMeta(model);
  145. }
  146. }