Учебник по Showcase: Простая форма

Материал из Course Orchestra
Перейти к: навигация, поиск

Внимание! Изложенная здесь информация устарела! В качестве учебника следует использовать https://share.curs.ru/webhelp/ (work in progress).


В настоящее время при построении приложений повсеместно используются HTML-формы. Они позволяют вводить и отправлять на сервер необходимую для обработки информацию. Однако стандартные HTML-формы имеют ряд недостатков. Во-первых, реализация HTML-формы сильно связана с клиентским языком сценариев, например JavaScript, с помощью которого выполняется проверка корректности значений полей формы, изменение значений одних полей формы на основе значений других полей и многие другие стандартные операции. В результате создание HTML-страниц, содержащих формы, становится достаточно сложной задачей и требует определенных навыков программирования. Во-вторых, поскольку HTML не определяет механизм связывания данных с элементами форм, то первоначальная инициализация значений полей формы и поддержка состояния просмотра страницы является серьезной проблемой. Стандартный подход приводит к смешению дизайна Web-страниц и кода на развитом языке программирования (например, Java, Perl или PHP), и получается, что без переделки кода изменить представление информации практически невозможно. Наконец, результат заполнения обычной HTML-формы представляется в виде набора пар имя-значение, что затрудняет их дальнейшую обработку и сохранение в базах данных.

Для решения перечисленных выше проблем консорциумом W3С был разработан новый подход к созданию форм в Web-приложениях под названием XForms. Основным отличием XForms от стандартных форм HTML является использование формата XML как для задания набора визуальных элементов управления формы, так и для первоначальной инициализации значений полей формы и пересылки ее значений на сервер с целью обработки. Это позволяет обрабатывать результаты и сохранять полученный XML в БД. Более того, XForms отделяют данные и логику форм от их представления. Большая часть стандартных операций теперь включается в состав XForms, что сокращает потребность в использовании клиентских сценариев. Более того, поскольку XForms является преемником HTML-форм, то все возможности HTML-форм доступны и в XForms.

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

  • xml, в котором будут храниться данные;
  • представление этих данных на экране с возможностью их редактирования, написанное на языке xforms.

Панель с новым элементом может выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<datapanel>
   <tab id="1" name="Сотрудники и оргструктура">		
      <element id="20" type="webtext" proc="orgButtons"/>
      <element id="30" type="grid" proc="orgGrid"/>	
      <element id="40" type="xforms" template="orgCard.xml" proc="orgCard" neverShowInPanel="true">
         <proc id="proc1" name="orgCardSave" type="SAVE"/>
      </element>		
   </tab>	
</datapanel>

Процедура orgGrid может остаться без изменений, а в процедуре orgButtons необходимо в переменной @xformssettings прописать следующее значение:

<properties>		
   <event name="single_click" linkId="1">
      <action show_in="MODAL_WINDOW">
         <main_context>current</main_context>
         <modalwindow caption="Добавление подразделения" height="800" width="720"/>
         <datapanel type="current" tab="current">
            <element id="40"/>                                    
         </datapanel>
      </action>
   </event>  				
</properties>
, чтобы в модальном окне открывался элемент типа xforms.

Обратите внимание на следующие параметры элемента типа xforms:

  • атрибут @proc, в котором содержится процедура, возвращающая xml c данными и xml, описывающий дополнительные свойства формы;
  • атрибут @template, в котором прописано название шаблона, написанного на языке xforms. Сам файл шаблона расположен по адресу %userdataname%/xforms;
  • атрибут @neverShowInPanel="true", означающий, что данный элемент никогда не будет отображаться на информационной панели. То есть его отображение возможно только в модальном окне;
  • новый тэг <proc>, имеющий тип SAVE, где в атрибуте name указано имя процедуры сохранения данных формы.

Простейшая процедура загрузки данных в элемент xforms выглядит следующим образом:

ALTER PROCEDURE [dbo].[orgCard]  
   @main_context varchar(512)='',  
   @add_context varchar(512)='',  
   @filterinfo xml='',  
   @session_context xml='',  
   @element_Id varchar(512)='',  
   @xformsdata xml output,  
   @xformssettings xml output  
AS  
BEGIN  
   SET NOCOUNT ON;  

   set @xformsdata = '
      <schema xmlns="">
         <record id="'+cast(newid() as nvarchar(50))+'" name=""/>
      </schema>'		

   set @xformssettings = '
      <properties>
         <event name="single_click" linkId="1">
            <action>
               <main_context>current</main_context>
               <datapanel type="current" tab="current">
                  <element id="30"/>
               </datapanel>
            </action>
         </event>
      </properties>'

END

Она возвращает два параметра:

  • @xformsdata - xml c данными, которые будут отображаться в форме;
  • @xformssettings - описание действий, которые будут происходить после закрытия формы.

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

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events"
    xmlns:xf="http://www.w3.org/2002/xforms">
    <head>
	
        <xf:model id="mainModel">
            <xf:instance id="mainInstance">
                <schema xmlns=""/>
            </xf:instance>
        </xf:model>

    </head>
	
    <body>
        <!--<xf:output value="serialize(instance('mainInstance'))"/>-->

        <div style="float: left; clear: both;">
            <xf:input class="textArea" style="font-size: small; height: 34px;"
                ref="/schema/record/@name">
                <xf:label>Наименование подразделения: </xf:label>
            </xf:input>
        </div>

        <div style="float: left; clear: both; margin-top:30px;">
            <xf:trigger>
                <xf:label>Сохранить и закрыть</xf:label>
                <xf:action ev:event="DOMActivate">
                    <xf:load
                        resource="javascript:gwtXFormSave('xformId','1',  Writer.toString(xforms.defaultModel.getInstanceDocument('mainInstance')))"/>
                    <xf:message>Данные сохранены</xf:message>
                </xf:action>
            </xf:trigger>

            <xf:trigger>
                <xf:label>Закрыть</xf:label>
                <xf:action ev:event="DOMActivate">
                    <xf:load resource="javascript:gwtXFormFilter('xformId','1', null)"/>
                </xf:action>
            </xf:trigger>
        </div>

    </body>
</html>

Рассмотрим простейший шаблон формы. Он служит для визуального представления формы на экране и заполнения ее данными, поэтому содержит как общие html-тэги, так и специальные тэги языка XForms. Как и любая html-страница, шаблон имеет следующую упрощенную структуру:

<html>
    <head>  
      ...
    </head>
    	
    <body>  
      ...
    </body>
</html>

В тэге <head> прописываются служебная информация о странице. В том числе тэг <xf:model id="mainModel">, в котором прописывается описание модели.

В тэге <xf:instance id="mainInstance"> указывается тот xml, который будет подгружен, если процедура возвращает @xformsdata = null. Если же @xformsdata не равна null, то в mainInstance прописывается значение @xformsdata.

По умолчанию все xpath-пути работают с экземпляром mainInstance (т.е. выражение instance('mainInstance')/record/@name эквивалентно /schema/record/@name)

Основная информация о прорисовке элементов содержится html-тэге <body>. В нем можно использовать как стандартные элементы для верстки (в нашем случае это <div>), так и элементы xforms. Выражение <xf:output value="serialize(/schema)/"> позволяет отобразить весь xml с данными, который мы редактируем с помощью формы. Именно этот xml мы получаем с сервера при загрузке, и именно его мы будем позднее отправлять на сервер для обработки. Этот элемент чаще нужен для отладки, чтобы в любой момент понимать, какие значения находятся в xml с данными. В дальнейших примерах этот элемент будет закомментирован. Обучаемому лучше держать эту строчку НЕзакомменченной, чтобы наблюдать, что происходит в /schema.

Далее в шаблоне прописан простейший элемент для ввода данных <xf:input ref="/schema/record/@name">, где в атрибуте @ref указан путь, по которому будет хранится введенное значение. После ввода значения и выходе из элемента (кнопка tab или щелчок мышкой на свободном пространстве), в отображаемом выше xml появится новое значение по указанному в атрибуте @ref пути.

Взаимодействие с сервером после ввода данных осуществляется с помощью кнопок, которые прописаны на языке xforms:

<xf:trigger>
   <xf:label>Сохранить и закрыть</xf:label>
   <xf:action ev:event="DOMActivate">
      <xf:load resource="javascript:gwtXFormSave('xformId','1',  Writer.toString(xforms.defaultModel.getInstanceDocument('mainInstance')))"/>
      <xf:message>Данные сохранены</xf:message>
   </xf:action>
</xf:trigger>
<xf:trigger>
   <xf:label>Закрыть</xf:label>
   <xf:action ev:event="DOMActivate">
      <xf:load resource="javascript:gwtXFormFilter('xformId','1', null)"/>
   </xf:action>
</xf:trigger>

Подробнее мы про них поговорим позже. Сейчас же нам важно, что при нажатии на них происходит запуск двух js-процедур:

  • javascript:gwtXFormSave('xformId','1', Writer.toString(xforms.defaultModel.getInstanceDocument('mainInstance')))
  • javascript:gwtXFormFilter('xformId','1', null)

Первый параметр фиксирован и всегда равен 'xformId'. Второй параметр - это linkId, который будет отрабатываться при закрытии формы (все linkId указаны в параметре @xformssettings). Третий параметр - полный путь к xml с данными на языке js (этот параметр также фиксирован) Основное отличие двух процедур друг от друга состоит в том, что перед обработкой действия по linkId процедура gwtXFormFilter просто закрывает форму, а gwtXFormSave запускает процедуру сохранения, описанную в информационной панели (<proc id="proc1" name="orgCardSave" type="SAVE"/>):

ALTER PROCEDURE [dbo].[orgCardSave]  
   @main_context nvarchar(512)='',  
   @add_context nvarchar(512)='',  
   @filterinfo xml='',  
   @session_context xml='',  
   @element_Id nvarchar(512)='',  
   @xformsdata xml='',  
   @error_mes nvarchar(512)='' output  
AS  
BEGIN  
 
   SET NOCOUNT ON;  
   declare 
      @org_name as nvarchar(255)

   set @org_name = @xformsdata.value('(/schema/record/@name)[1]','nvarchar(255)')
	
   insert into "orgStructure" (uid,name) 
      values (newid(),@org_name)

END

Тот xml, который мы редактировали в форме и который хотим далее обработать в процедуре сохранения прописывается в параметре @xformsdata. Обратите внимание, что у данной процедуры в числе входящих параметров указаны все стандартные элементы контекста. Сама же процедура просто достает из @xformsdata название отдела и сохраняет его в таблицу с новым uid. Обратите внимание, что сохранение производится с совершенно новым ID, а не с тем, который мы в элементе xform'ы <record> задали. В дальнейшем процедуры сохранения будут слегка усложнены.

После сохранения формы будет обработан linkId = 1, который перерисовывает элемент с id="30". Это сделано для того, чтобы в данном гриде отобразилась новое сохраненное значение отдела.