Динамический выбор формы схемы Angular6

#angular #angular-material #jsonschema

#angular #angular-материал #jsonschema

Вопрос:

Я использую форму схемы Angular6 JSON

Где 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": {}
}
  

И я хотел бы иметь возможность динамически загружать карту заголовков с помощью пользовательской функции обратного вызова или указывать URL-адрес для вызова, чтобы получить данные карты заголовков.

Я видел падение библиотек, написанных на angular.js но мне нужно решение, которое работает для Angular и Material.

Любые предложения приветствуются!

Ответ №1:

В прошлом у меня были проблемы с angular-schema-form-dynamic-select , и я отказался от этого в пользу ванильного решения, которое затем мне пришлось перенести на angular6-json-schema-form , когда мы получили зеленый свет для переноса проекта с AngularJS на Angular 7. Хотя для этого требуется довольно много усилий, это позволяет вам заполнять данные или делать все, что вы хотите при инициализации формы, используя только формы ванильной схемы.

В моем контексте | async это было невозможно, потому что по независящим от меня причинам выборка данных вернула обещание bluebird, которое несовместимо с асинхронным фильтром. Если у вас нет этого ограничения, я бы попробовал сначала посмотреть, сработает ли предложение @Mic.

Я создал помощник для получения результата promise (в моем случае, конечной точки списка 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 = resu<
        })
        .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>
  

Не так аккуратно, как выпадающее расширение, но выполняет свою работу.

Ответ №2:

Я не пробовал это сам, но из readme видно, что привязка к [layout]="yourJsonFormLayout" атрибуту с yourJsonFormLayout обновлением по вашему требованию будет работать.

Вы также можете использовать | async канал для загрузки данных с запрашиваемого URL-адреса, настраивая формат, как в

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