Действия
Действия N2o выполняются с помощью библиотеки Redux. Действия Redux меняют состояние React компонентов и отправляют запросы на сервер.
Местоположение действий
Действия задаются на странице <page>
, в компонентах страницы, а также в меню структуры приложения <application>
.
Подробнее о каждом из этих случаев будет рассказано далее.
Действия в меню
Одним из вариантов использования действия является задание его в меню <menu-item>
структуры приложения.
<application xmlns="http://n2oapp.net/framework/config/schema/application-3.0">
<header title="Хедер">
<nav>
<menu-item name="Открыть страницу">
<open-page page-id="page" route="/login"/>
</menu-item>
</nav>
</header>
</application>
Действия в кнопках страницы
Пожалуй, самым частым вариантом является использование действий в кнопках страницы.
В данном случае неважно, чем является кнопка: стандартной кнопкой, полем-кнопкой,
кнопкой в ячейке или в выпадающем меню.
При клике по ней будет выполняться указанное действие.
<page xmlns="http://n2oapp.net/framework/config/schema/page-4.0">
...
<toolbar>
<button label="Сохранить документ">
<invoke operation-id="saveDocument"/>
</button>
</toolbar>
</page>
Действия на странице
При многократном использовании одного действия существует возможность вынести его в отдельный элемент <actions>
при этом указав id
.
Для обращения к этому действию достаточно указать его идентификатор в атрибуте action-id
.
<page xmlns="http://n2oapp.net/framework/config/schema/page-4.0">
...
<actions>
<!-- Указываем id действия -->
<action id="save">
<invoke operation-id="saveDocument"/>
</action>
</actions>
<toolbar>
<!-- Обращаемся к действию по его id -->
<button label="Сохранить документ" action-id="save"/>
</toolbar>
</page>
Действия в виджетах
Аналогично страницам действия можно определить и внутри виджетов.
<form>
...
<actions>
<!-- Указываем id действия -->
<action id="save">
<invoke operation-id="saveDocument"/>
</action>
</actions>
<toolbar>
<!-- Обращаемся к действию по его id -->
<button label="Сохранить документ" action-id="save"/>
</toolbar>
</form>
Задание действия на странице или в виджете определяет область видимости. Кнопки виджета могут ссылаться на действия страницы, а вот кнопки страницы на действия виджета не могут.
Внутренние действия компонентов
Не только кнопки способны выполнять действие по клику.
Это может быть клик по строке таблицы, клик по определенному полю или ячейке.
Во всех этих компонентах также есть возможность либо описать действие внутри элемента, либо обратиться по его id.
<table>
<columns>
<column text-field-id="status">
<!-- Отправка статуса при клике по чекбокс-ячейке таблицы -->
<checkbox enabled="true">
<invoke operation-id="checkStatus"/>
</checkbox>
</column>
</columns>
<rows>
<!-- Открытие страницы при клике по строке таблицы -->
<click>
<show-modal page-id="modal"/>
</click>
</rows>
</table>
Действия открытия окон и страниц
Отрытие окон
Открытие страниц
Проброс кнопок и действий в открываемые страницы
Кнопки и действия на странице можно переопределять в открывающих страницах. Это удобно когда необходимо использовать одну и ту же страницу, отличающуюся только кнопками и действиями.
<show-modal page-id="personCard">
<actions>
<action id="saveAction">
<invoke operation-id="save"/>
</action>
</actions>
<toolbars>
<toolbar>
<!-- кнопка ссылается на прокидываемое действие saveAction -->
<button label="Сохранить" action-id="saveAction"/>
</toolbar>
</toolbars>
</show-modal>
<show-modal page-id="personCard">
<toolbars>
<toolbar>
<button label="Копировать">
<!-- действие использует прокидываемый источник ds1 -->
<copy copy-datasource="modal_ds" target-datasource="ds1"/>
</button>
</toolbar>
</toolbars>
<datasources>
<parent-datasource id="ds1"/>
</datasources>
</show-modal>
Действие редактирования списка данных без обращения к серверу
Одним из типовых вариантов использования списковых данных являются таблицы и мультифилдсеты. В таком случае каждая строчка или каждый набор полей - это элемент списка.
С помощью действия <edit-list>
список может быть модифицирован одним из привычных способов.
Для модификации доступны 5 возможных операций: create
, createMany
, update
, delete
, deleteMany
.
<table datasource="ds" selection="checkbox">
<columns>
...
</columns>
<toolbar>
<button label="Удалить выбранные строки">
<edit-list
operation="deleteMany"
datasource="ds"
model="datasource"
item-datasource="ds"
item-model="multi"/>
</button>
</toolbar>
</table>
Случай с изменением данных строки в форме и последующем сохранении в таблицу:
<form datasource="formDs">
<fields>
...
</fields>
<toolbar>
<button label="Сохранить">
<edit-list
operation="update"
primary-key="id"
datasource="tableDs"
model="datasource"
item-datasource="formDs"
item-model="resolve"/>
<close/>
</button>
</toolbar>
</form>
Обратите внимание на атрибут primary-key
в последнем примере.
В нем указывается поле, по которому среди списка записей будет искаться нужная, для операций изменения или удаления.
Учтите, что указанное поле должно иметь уникальные значения.
В конце важно упомянуть о такой важной особенности действия <edit-list>
, как отсутствие запроса на сервер.
Можно заметить, что, если после модификации списка обновить страницу, то все данные потеряются.
Однако отсутствие запроса на сохранение ни в коем случае не является недостатком действия,
а скорее возможностью более гибко настроить момент, в который это сохранение произойдет.
Но как же тогда сохранить на сервер только что внесенные изменения?
Для этого достаточно использовать действия <submit>
или <invoke>
сразу после <edit-list>
.
Вызов нескольких действий подряд создаст так называемую последовательность действий или мульти действие,
которому и будет посвящен следующий раздел.
Подробнее о действии edit-list
Последовательность действий и ветвления
До этого момента в примерах использовались только простые одиночные действия. Они покрывают большую часть возможных случаев. Но как поступить, если необходимо выполнить несколько действий или выполнить действие при определенном условии? Об этом и пойдет речь ниже.
Мульти действия
Иногда возникает необходимость вызывать целую цепочку последовательных действий. N2o позволяет сделать это. И во всех местах, где до этого вызывались одиночные действия, можно также вызвать последовательность действий.
В таком случае указанные действия будут выполняться одно за другим, и если предыдущее действие выполнило сь неудачно (ошибка), то все последующие действия не выполняются.
Если действие привело к ошибке, то все предыдущие действия не отменяются.
<button xmlns="http://n2oapp.net/framework/config/schema/page-4.0">
<!-- Копируем данные в источник данных ds2 -->
<copy source-model="resolve" source-datasource="ds" target-datasource="ds2" target-model="resolve"/>
<!-- Сохраняем данные источника ds2 -->
<submit datasource="ds2"/>
<!-- Открываем страницу page -->
<open-page page-id="page" route="/open"/>
</page>
Абсолютно аналогичным образом работает определение мульти действия на странице или в виджете.
<page xmlns="http://n2oapp.net/framework/config/schema/page-4.0">
...
<actions>
<!-- Указываем id действия -->
<action id="multiSave">
<invoke operation-id="saveDocument"/>
<invoke operation-id="savePersonInfo"/>
</action>
</actions>
<toolbar>
<!-- Обращаемся к действию по его id -->
<button label="Сохранить данные страницы" action-id="multiSave"/>
</toolbar>
</page>
При использовании мульти действий существует одно естестве нное ограничение. Действие открытия страницы или окна завершает цепочку, а значит все действия, расположенные после него не будут выполнены.
Условный оператор if-else для действий
В зависимости от значения полей существует возможность выбирать какое действие или последовательность действий будут выполнены.
Оператор if-else работает по общепринятым правилам:
- если выражение
test
в элементе<if>
верно, то выполняется действие внутри элемента<if>
- иначе проверяется выражение
test
в элементе<else-if>
, и если оно верно то выполняется действие внутри него - если все предыдущие проверки были ложны, то выполняется действие внутри элемента
<else>
Ограничений на количество элементов <else-if>
нет.
<button>
<!-- Выполняем операцию и получаем ответ -->
<invoke operation-id="saveInfo"/>
<!-- код ответа равен 1: сообщение об успехе -->
<if test="responseCode == 1">
<alert text="Действие выполнено успешно" color="success"/>
</if>
<!-- код ответа равен 2: сообщение о неудаче -->
<else-if test="responseCode == 2">
<alert text="Произошла ошибка" color="danger"/>
</else-if>
<!-- иначе: повторяем операцию -->
<else>
<invoke operation-id="saveInfo"/>
</else>
</button>
Оператор if-else действий может содержать внутри себя оператор if-else, переключатель switch/case и прочие действия.
Подробнее об операторе if-else для действий
Переключатель действий switch/case
Существует возможность использовать более упрощенную версию if-else - оператор switch/case.
Он позволяет сопоставлять значение атрибута value
элемента <case>
со значением поля,
указанного в атрибуте value-field-id
элемента <switch>
.
- если совпадение найдено, то будет выполнено действие или последовательность действий, указанная в теле элемента
<case>
- если совпадений нет, то будет выполнено действие из элемента
<default>
<button>
<switch value-field-id="document.type">
<case value="1">
<show-modal page-id="passport" page-name="Страница паспорта"/>
</case>
<case value="2">
<show-modal page-id="inn" page-name="Страница ИНН"/>
</case>
<default>
<open-page page-id="unknown_document" page-name="Страница заполнения документа"/>
</default>
</switch>
</button>
Переключатель действий switch/case может содержать внутри себя оператор if-else, переключатель switch/case и прочие действия.