Окна и диалоги

Всплывающее окно — это абсолютно спозиционированный элемент в DOM-дереве. Никакой другой логики контрол в себе не несет. Контрол не знает о своей позиции, окружении и шаблоне, который отрисовывает.

В следующем примере показана работа стековых и диалоговых окон:

Пример
Исходный код

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

Общая схема конфигурации всплывающих окно

Рис. 1. Схема взаимодействия контрола с всплывающими окнами.

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

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

Добавление открывающего контрола в шаблон

На этом этапе в вёрстку родительского контрола (контрола, из которого планируется открывать всплывающее окно) нужно добавить открывающий контрол или Opener.

Opener открывает всплывающее окно Popup, реагируя на событие родительского контрола MyComponent.

Для организации взаимодействия сo всплывающим окном, требуется добавить Opener в вёрстку MyComponent.

Далее для контрола Opener нужно задать конфигурацию. Список общих опций приведён в таблице.

НазваниеОписание
nameИмя открывающего контрола. Используется в обработчике открытия всплывающего окна.
templateШаблон всплывающего окна.
templateOptionsСобственные опции, передаваемые в шаблон. Опция актуальна, когда задан собственный шаблон template.

Остальные опции описаны в API класса конкретного контрола.

Для диалога подтверждения конфигурация передается только динамически — через метод open().

<!-- WML -->
<Controls.popup:Dialog name="dialog" template="Examples/Popup/templates/dialog" />

Создание шаблона всплывающего окна

Внешний вид отображаемого всплывающего окна определяется его шаблоном.

В создаваемых шаблонах подключаются стандартные шаблоны с базовой раскладкой. На их основе строится вёрстка всплывающих окон. В шаблонах определены позиции с изменяемым контентом.

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

Пример 2. Ниже показано содержимое шаблона Examples/Popup/templates/dialog.tmpl. Опции шаблона передаются через templateOptions.

<!-- WML -->
<Controls.popupTemplate:Dialog headingCaption="Создание категории">
   <ws:headerContentTemplate>
      ...
   </ws:headerContentTemplate>
   <ws:bodyContentTemplate>
      ... 
   </ws:bodyContentTemplate>
</Controls.popupTemplate:Dialog>

Пример 3. Передача пользовательской опции type в шаблон всплывающего окна Examples/Popup/TestDialog.

<!-- WML -->
<Controls.popupTemplate:Dialog headingCaption="PopupManager">
   <ws:headerContentTemplate>
      <div>
         <Controls.buttons:Button caption="Закрыть {{_options.type}}" on:click="_close()"/>
      </div>
   </ws:headerContentTemplate>
   <ws:bodyContentTemplate>
      ...
   </ws:bodyContentTemplate>
</Controls.popupTemplate:Dialog>

Значение опции type передано в Controls.popup:Dialog через templateOptions.

<!-- WML -->
<Controls.popup:Dialog name="modalDialog" modal="{{true}}" template="Controls-demo/Popup/TestDialog">
   <ws:templateOptions type="dialog"/>
</Controls.popup:Dialog>

Создание обработчика, открывающего окно

Необходимо определить событие контрола MyComponent. В нашем примере всплывающее окно открывается при клике по кнопке. Она добавлена в вёрстку контрола рядом с открывающим контролом. На клик кнопки создан обработчик, вызывающий метод openDialog().

<!-- WML -->
<div>
   <Controls.popup:Dialog name="dialog" />
   <Controls.buttons:Button name="dialogButton" caption="Диалог" on:click="openDialog()"/>
</div>
// TypeScript
protected openDialog(): void {
    
   // this._children содержит экземпляры дочерних контролов.
   // Обращение к экземпляру производится через имя дочернего контрола.
    
   // Метод open() откроет всплывающий элемент.
   // В аргументах метода можно передать объект с настройками контрола.
   this._children.modalDialog.open();
},

Подробнее об отладке открытия окон и панелей можно прочитать здесь

Событие открытия всплывающего окна

При открытии любого всплывающего окна опенер оповещает о событии open. Чтобы на такое событие задать обработчик, выполните следующие действия:

  1. Откройте wml-файл, где описан опенер. Например, в контексте настоящей статьи мы назвали этот файл MyComponent.wml.
  2. Согласно синтаксису подписки на события, передайте опенеру атрибут on:open с именем функции-обработчика.
<!-- WML -->
<Controls.popup:Dialog
    name="notification"
    on:open="_notifyOpenHandler()">
    ...
</Controls.popup:Dialog>
  1. Откройте JS-модуль контрола, например в настоящей статье это MyComponent.js, и опишите функцию-обработчик.
// TypeScript
protected _notifyOpenHandler(): void {
    // Прикладной код, обрабатывающий открытие окна.
    ...
},

Обновление опций открытого окна

Для обновления опций в уже открытом окне необходимо повторно вызвать метод open, передав в него новые значения опций:

import {DialogOpener} from 'Controls/popup';
 
this._dialog = new DialogOpener();
 
openDialog() {
    this._dialog.open({
        template: 'Example/MyDialogTemplate',
        opener: this._children.myButton,
        templateOptions: {
            myChangedOptons: this._controlState
        }
    });
},
changeState(newValue) {
    this._controlState = newValue;
     
    // Если диалог открыт, пробросим ему новое значение опции myChangeOptions
    if (this._dialog.isOpened()) {
        this.openDialog();
    }
}

Обратите внимание!

Если вы используете контрол-opener в верстке и описываете его шаблон внутри опции template, то значения состояний, передаваемых в этот шаблон, не будут синхронизированы с открытым окном.

<!-- WML -->
<Controls.popup:Dialog name="dialog">
<ws:template>
  <Controls.popupTemplate:Dialog headingCaption="{{ _myCaption }}">
     <ws:bodyContentTemplate>
        <!-- Пользовательский контент -->
     </ws:bodyContentTemplate>
  </Controls.popupTemplate:Dialog>
</ws:template>
</Controls.popup:Dialog>
Таким образом, после того, как мы откроем окно и изменим состояние "_myCaption", опция **headingCaption** не изменится. Чтобы все работало корректно, используйте открываторы окон из кода.

Создание обработчика, закрывающего окно

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

В следующем примере обработчик создан со стороны всплывающего окна:

<!-- WML -->
<Controls.buttons:Button caption="Закрыть" on:click="_close()" />
// TypeScript
protected _close(): void {
   // Оповещаем о событии.
   this._notify('close', [], {bubbling: true});
},

В следующем примере обработчик создан со стороны родительского контрола, открывшего это окно.

// TypeScript
// this._children содержит экземпляры дочерних контролов.
// Обращение к экземпляру производится через имя дочернего контрола.
 
this._children.stack.close();

Событие о закрытии всплывающего окна

При закрытии любого всплывающего окна опенер оповещает о событии close. Чтобы на это событие задать обработчик, выполните следующее:

  1. Откройте WML-шаблон, где описан опенер. Например, в контексте настоящей статьи мы назвали этот файл MyComponent.wml.
  2. Согласно синтаксису подписки на события, передайте опенеру атрибут on:close с именем функции-обработчика.
<!-- WML -->
<Controls.popup:Dialog
    name="notification"
    on:close="_notifyCloseHandler()">
    ...
</Controls.popup:Dialog>
  1. Откройте JS-модуль контрола. Например, в настоящей статье это файл MyComponent.js. В модуле опишите функцию-обработчик.
// TypeScript
protected _notifyCloseHandler(): void {
    // Прикладной код, обрабатывающий закрытие окна.
    ...
},

Передача данных из всплывающего элемента в родительский контрол. Событие sendResult.

В отдельных случаях необходимо передать данные из всплывающего элемента в родительский контрол. Для этого использую обработчики событий, а в случае всплывающего окна — обработчик события sendResult.

В родительском контроле опишете функцию-обработчик для события result, которая выполнится, когда всплывающее окно оповестит о событии sendResult. Количество аргументов обработчиков (а также — типы их значений) зависит от конкретной реализации всплывающего окна.Например, для опенера "Окна выбора из справочника" тип возвращаемого значения зависит от количества выбранных элементов коллекции: RecordSet — для одного выбранного элемента, для нескольких элементов, выбранных из одной вкладки; IList — для выбора нескольких элементов из разных вкладок.

  1. В родительском контроле:
    • в верстке открывающего контрола в опции всплывающего окна добавлен обработчик:
<!-- WML -->
<Controls.popup:Stack name="stack"
    on:result="_notifyResultHandler()"
    template="My/Template/For/Stack" />
// TypeScript
protected _notifyResultHandler(event, result): void  {
    if (result) {
        alert(result);
    }
}
  1. В шаблоне всплывающего окна.
<!-- WML -->
<Controls.buttons:Button
   caption="Сохранить"
   on:click="_onClick()"/>
// TypeScript
protected _onClick(): void {
   this._notify(
      'sendResult',
      // Передаем результат. 
      [... , ... ],
      {bubbling: true}
   );
}

Типовые проблемы при работе со всплывающими окнами