Angular6模式表单动态选择

时间:2019-03-13 18:29:19

标签: angular angular-material jsonschema

我正在使用Angular6 JSON Schema Form

其中的html select元素用json描述如下:

  {
"schema": {
  "type": "object",
  "title": "My Form",
  "properties": {
    "select1552420741389": {
      "type": "string"
    }
  },
  "required": [
    "select1552420741389"
  ]
},
"layout": [
  {
    "key": "select1552420741389",
    "type": "select",
    "multiple": false,
    "notitle": false,
    "title": "Select",
    "titleMap": [
      {
        "name": "Option 1",
        "value": "option1"
      },
      {
        "name": "Option 2",
        "value": "option2"
      }
    ]
  }
],
"data": {}
}

我想选择通过自定义的回调函数动态加载titleMap或指定要调用的URL以获取titleMap数据。

我已经看到了用angular.js编写的库的下降,但是我需要一个适用于Angular和Material的解决方案。

任何建议,不胜感激!

2 个答案:

答案 0 :(得分:1)

我过去在angular-schema-form-dynamic-select上遇到过一些问题,放弃了它,转而使用香草解决方案,然后当我们获得了将项目从AngularJS迁移到[]的许可时,我不得不移植到angular6-json-schema-form Angular7。尽管它确实需要大量的润滑脂,但它允许您填充数据或仅使用原始模式表单来进行表单初始化中要执行的其他任何操作。

在我的上下文中,| async不是一个选择,因为出于我无法控制的原因,数据获取返回了一个蓝鸟承诺,该承诺与异步过滤器不兼容。如果您没有此限制,我将尝试看看@Mic的建议是否首先起作用。

我创建了一个用于获取承诺结果的助手(在我的情况下是HAL REST列表端点),并将其转换为标题图。在我的情况下,我总是想要元素的name或失败的元素description,所以我要这么做:

  // returns a [{name: name, value: link}, ...] mapping of items for form
  // display based on a promise whose result is a list of entities
  private formify(promise) {
    return promise
        .then(result => result._embedded[Object.keys(result._embedded)[0]].map(element => ({
          name: element.name || element.description,
          value: element._links.self.href
        })))
        .catch(error => console.log(error));
  }

然后是另一个创建onInit回调的帮助程序:

  // returns an onInit callback for a simple select that is populated with
  // the list of entities supplied by the given promise
  private getStandardPromiseOnInit(formItem, promise) {
    return () => this.formify(promise)
        .then(function(result) {
          formItem.titleMap = result;
        })
        .catch(error => console.log(error));
  }

然后我在表单项中添加一个onInit字段:

  formItem.onInit = this.getStandardPromiseOnInit(formItem, callToRestService());

在处理完我的表单定义对象(它使用AngularJS语法,因为这是一个端口)之后,看起来会像这样:

[
  {
    "key": "type",
    "placeholder": "...",
    "type": "select",
    "onInit": <function....>
  },
  {
    "key": "equipment",
    "placeholder": "...",
    "type": "select",
    "onInit": <other function....>
  },
  ...
]

我有一项用于获取可完成此工作的表单定义的服务。

然后在初始化表单组件时,我递归地遍历表单声明,寻找onInit回调并执行它们:

  form: any;
  ready: boolean;

  ngOnInit() {
    ...
    this.populateForm();
  }

  populateForm: Function = () => {
    let onInits = [];
    if (this.form) {
      // recursively traverse the form json
      let traverse = item => {
        if (item.items) {
          item.items.map(traverse);
        } else if (item.tabs) {
          item.tabs.map(traverse);
        }

        // call onInit callbacks
        if (item.onInit) {
          onInits.push(item.onInit());
        }
      };
      this.form.map(traverse);
    }

    Promise.all(onInits)
        .then(() => this.ready = true)
        .catch(error => {
          // error handling and message display
        });
  };

this.ready表示所有承诺均已解决,因此可以在不强制重绘的情况下呈现表单:

<json-schema-form *ngIf="ready"
    ...
    [form]="form" 
    ...
>
</json-schema-form>

不如插入式扩展程序那么整洁,但是可以完成工作。

答案 1 :(得分:0)

我自己没有尝试过,但是从readme看来,绑定到[layout]="yourJsonFormLayout"属性,并根据需要更新yourJsonFormLayout会起作用。

您还可以使用| async管道从查询的URL加载数据,并按照以下格式进行调整

this.yourJsonFormLayout = http.get(...).pipe(map(...format your object...));