Перейти к содержанию

Использование вложенных форм#

Одним из основных механизмов платформы является поддержка вложенности форм. Данный механизм позволяет в любую форму добавлять различные формы в качестве вложенных и, соответственно, любую форму использовать в качестве вложенной. Каждая форма любого приложения на базе платформы является вложенной по отношению к корневой форме.

У каждого экземпляра любого класса формы приложения имеется свойство parent, в котором хранится ссылка на экземпляр его родительской формы. Это свойство является пустым только у экземпляра корневой формы. При обращении к экземпляру родительской формы можно вызывать любые публичные методы, реализованные в его классе.

Для работы со вложенными формами имеется специализированный контрол NestedForm. Он служит в качестве контейнера для вложенных форм в контексте родительских. Все манипуляции со вложенными формами осуществляется с его помощью. Добавлять формы в качестве дочерних можно как в шаблоне, так и динамически в методах текущей формы. Также имеется возможность добавлять формы документов и реестров.

К вложенным формам применяются те же правила вёрстки, как и к обычным формам.

Важной особенностью работы вложенных форм является отключение панели инструментов (контрола ToolBar) - то есть, добавленные в шаблоне контролы ToolBar и Tool не будут созданы, как и свойство toolBar класса формы. Поэтому не рекомендуется использовать добавление обработчиков событий нажатия кнопок панели в конструкторе форм, которые могут быть использованы в качестве вложенных.

Работа с дочерними формами#

Примеры, рассмотренные ниже, описаны в форме демонстрационного проекта: nestedFormDemo.

Добавление в шаблоне#

Простейший способ добавить дочернюю форму - это определить её в шаблоне текущей формы:

1
2
3
<Group id="simpleForms" caption="Простые формы" editorWidth="3">
        <NestedForm id="nested" form="./nestedSmall" editorWidth="3"/>
    </Group>

В шаблоне достаточно расположить контрол NestedForm и указать в его свойстве form относительный путь к файлу класса требуемой формы. Таким образом можно добавлять только аналитические формы (наследники класса Form), поскольку в шаблоне нет возможности определить требуемые параметры для классов документа и реестра.

Динамическое добавление#

Для динамического добавления вложенной формы необходимо использовать метод create текущей формы. Обязательными параметрами в этом методе являются поля FormClass и nestedForm. Первый параметр должен быть ссылкой на класс нужной дочерней формы. Второй - ссылкой на контрол NestedForm, в который новая дочерняя форма будет вложена.

1
2
3
4
<Group editorWidth='12'>
        <Button id="rd" value="reload data in nested" clicked="reloadNested"/>
        <NestedForm id='NestedForm' editorWidth='9'/>
    </Group>

Поскольку при динамическом добавлении дочерней формы можно использовать различные классы форм, задавать свойство form контролу NestedForm в шаблоне не требуется.

import { Form, NestedForm, PageBlocker, ModelSource } from 'ecosoft-lexema8'
import template from './nestedFormDemo.xml'
import NestedSmall from './nestedSmall'
import BrokenForm from './brokenForm'
import nestedDocument from '../chocolate/ingredientForm'
import Project from '../chocolate/ingredient.model.json'

export default class NestedDemo extends Form {
  constructor (args) {
    super(args)
    this.create({
      FormClass: nestedDocument,
      nestedForm: this.controls.NestedForm,
      formParams: {
        id: 6
      }
    }).always(() => {
      PageBlocker.off()
    })
  }

  //...

}

При вызове метода в качестве обязательных параметров передаётся импортированный класс требуемой вложенной формы и ссылка на нужный контрол NestedForm. В примере, добавляемая в качестве вложенной, форма является документом, поэтому необходимо передавать обязательный параметр идентификатора документа.

Замена вложенной формы#

В случае, когда производится добавление вложенной формы в контрол NestedForm, в который уже была добавлена вложенная форма, старая форма будет уничтожена и вместо неё будет создана и добавлена новая. Таким образом, замена существующей формы сводится просто к вызову метода create текущей (родительской) формы:

1
2
3
4
5
6
7
8
9
 /**
   * Замена формы во вложенной форме.
   */
  replace () {
    this.create({
      FormClass: NestedSmall,
      nestedForm: this.controls.nested
    })
  }

Создание новой вложенной формы#

Используя механизм динамического создания контролов, можно добавлять вложенные формы, не объявляя их до этого в шаблоне:

  /**
   * Создание новой вложенной формы с простой формой внутри.
   */
  addSimple () {
    this.create({
      FormClass: NestedSmall,
      nestedForm: () => {
        const [nested] = this.controls.simpleForms.addControls([{
          Ctor: NestedForm,
          properties: {
            editorWidth: 3
          }
        }])

        return nested
      }
    })
  }

Здесь в параметр nestedForm метода создания вложенной формы передаётся функция, которая создаёт и возвращает новый контрол NestedForm для вложенной формы.

Аналогично, можно создавать новые вложенные формы для документов. Для этого, как и раньше, необходимо определить и передавать в метод создания вложенной формы идентификатор требуемого документа. В примере для этого используется контрол Lookup, который в качестве источника данных имеет модель нужного документа:

1
2
3
4
5
6
7
    <Group caption="Документы" editorWidth="9">
        <Group caption="Выбор" editorWidth="9">
            <Lookup id="doc" caption="Документ" valueChanged="docChanged"
                    dataSource="../chocolate/ingredient.model.json"/>
        </Group>
        <Group caption="Формы" id="docsForms" editorWidth="9"/>
    </Group>
    /**
   * Создание новой вложенной формы с документом внутри.
   */
  addDocument () {
    const { VCode: id } = this.controls.doc.value || {}

    if (!id) {
      this.services.dialog.error('Не выбран документ.')
    }

    PageBlocker.on()

    this.create({
      FormClass: nestedDocument,
      nestedForm: () => {
        const [nested] = this.controls.docsForms.addControls([{
          Ctor: NestedForm,
          properties: {
            editorWidth: 9
          }
        }])

        return nested
      },
      formParams: { id }
    }).always(() => {
      PageBlocker.off()
    })
  }

Создание нового документа во вложенной форме#

Во вложенной форме можно также создать новый документ. Для этого нужно воспользоваться методом генерации нового идентификатора документа у источника данных на соответствующей модели. Вложенные формы можно также добавлять во всплывающие окна (контрол PopupWindow):

    <PopupContainer>
        <PopupWindow id="newDocWindow" width="65%" isModal="true"
                     hPosition="center" vPosition="top">
            <ToolBar editorWidth="12">
                <Tool image="current-theme/images/controls/save.png" clicked="saveNewDoc"/>
                <Tool image="current-theme/images/controls/close.png" clicked="closeNewDoc"/>
            </ToolBar>
            <NestedForm id="newDoc" editorWidth="12"/>
        </PopupWindow>
    </PopupContainer>
  /**
   * Создание нового документа во вложенной форме.
   */
  createNewDoc () {
    const source = new ModelSource(Project)
    PageBlocker.on()

    source.genPrimaryKey().then(id => {
      return this.create({
        FormClass: nestedDocument,
        nestedForm: this.controls.newDoc,
        options: { isNew: true },
        formParams: { id }
      }).done(() => {
        this.controls.newDocWindow.open()
      })
    }).always(() => {
      PageBlocker.off()
    })
  }

Всплывающее окно

В данном примере перед созданием вложенной формы в контроле NestedForm, расположенном во всплывающем окне, производится генерация нового ключа для модели используемой формы документа. По окончании создания вложенной формы открывается всплывающее окно.

Обращение к дочерним формам#

Обращение к дочерним формам осуществляется через контролы NestedForm, в которые они были добавлены. Ссылка на экземпляры дочерних форм сохраняется в свойстве form соответствующего контрола.

  /**
   * Сохранение нового документа во вложенной форме.
   */
  saveNewDoc () {
    PageBlocker.on()

    this.controls.newDoc.form.save().done(() => {
      this.controls.doc.setDataSourceParameters({})
    }).always(() => {
      PageBlocker.off()
      this.controls.newDocWindow.close()
    })
  }

В данном примере производится вызов метода save() вложенной формы документа, ссылка на которую находится в свойстве form контрола NestedForm с идентификатором newDoc.

Другой пример:

1
2
3
  reloadNested () {
    this.controls.NestedForm.form.reloadData()
  }

Здесь вызывается метод reloadData() у вложенной формы, добавляемой в конструкторе текущей формы с примерами.