Adjusting the DataEditor xml

Smartsite 7.7 - ...

The Generate DataEditor wizard will generate a basic implementation of the DataEditor xml.

Edit Filetype example

When editing an existing record, the UI will look like the example shown above.
In this article, the xml is altered to provide a more user-friendly add/edit environment.

Dropdown list

Specifying the mime type for a specific filetype shouldn't be a simple textbox in which you have to type a number. Since it's a foreign key relation, you would expect a dropdown to select a value from.

To achieve this, change the nrmimetype field definition into this:

XML CopyCode image Copy Code
<field name="nrmimetype" caption="MIME_TYPE">
 <control type="dropdownlist">
  <itemset ref="is_mimetypes" />
  <properties>
   <property name="required">true</property>
   <property name="alert">You must select a mime type.</property>
  </properties>
 </control>
</field>

The data for the dropdown list will come from the itemset is_mimetypes. This itemset needs to be added to the dataeditor xml as well:

XML CopyCode image Copy Code
<itemsets>
 <load tablename="mimetypes" />
</itemsets>

When the data for a dropdown list comes from a "simple" table which includes a Nr column and a Name column, you only need to specify the tablename attribute.

Code must be unique

The FileTypes table does have an unique constraint on the code column within the database. So, when you try to add a FileType with a code which is already been used, you get the following error:

Unique constraint error

To enforce this constraint before a FileType can be saved, the DataEditor xml needs to be adjusted. In this case, we need a custom control for the code field, see the example below.

XML CopyCode image Copy Code
<field name="code">
 <control type="custom">
  <viewdata>
   <xf:input ref="cms:code" appearance="full" maxlength="20" navindex="1" id="cf_code">
    <xf:label>Code</xf:label>
    <xf:alert>
     <xf:output ref="instance('res')/code_required" />
     <xf:output ref="instance('res')/code_duplicate" />
     <xf:output ref="instance('res')/code_invalid" />
    </xf:alert>
    <xf:action ev:event="xforms-value-changed">
     <xf:setvalue ref="instance('validationresults')/field[@name='code']/@constraintvalid" 
      if="string-length(instance()/cms:entry/cms:code) != 0" 
      value="choose(string-length(instance()/cms:entry/cms:nr)=0,
       dataeditor:checkuniqueconstraint('filetypes','code', string(instance()/cms:entry/cms:code)),
       dataeditor:checkuniqueconstraint('filetypes','code', string(instance()/cms:entry/cms:code), 'nr', string(instance()/cms:entry/cms:nr)))" />
    </xf:action>
   </xf:input>
  </viewdata>
 </control>
</field>

A custom control is a control in which you have to specify the XForm logic yourself within a viewdata child element.

The example above is a standard textbox which allows 20 characters. It contains three different alert messages, one of them will be set relevant at the time, dependent on validation rules implemented in modellogic (discussed later on).

Furthermore, it contains handling when the input's value has been changed (the xf:action element, triggered when the event xforms-value-changed is fired).
When this action is executed, it calls a DataEditor XForms extension function to check the unique constraint and writes the result into the specified node/attribute.

Modellogic

The custom control isn't complete without some adjustments to the modellogic as well:

XML CopyCode image Copy Code
<modellogic>
 <xf:bind nodeset="cms:entry/cms:code" required="true()" type="dataeditor:genericCodeType" 
  constraint="instance('validationresults')/field[@name='code']/@constraintvalid='true'" />
 
 <xf:action ev:event="xforms-value-changed" ev:observer="cf_code">
  <xf:setvalue ref="instance()/cms:entry/cms:code" value="fn:upper-case(fn:replace(.,'[^A-Za-z0-9\-\._]',''))" />
 </xf:action>
 
 <xf:instance id="res">
  <resourcestrings xmlns="">
   <code_required>Code is verplicht. Specificeer een code.</code_required>
   <code_duplicate>Deze code is al in gebruik.</code_duplicate>
   <code_invalid>De opgegeven code is niet geldig. De code moet beginnen met een karakter uit de reeks A-Z of '_', 
    gevolgd door 1 tot 49 karakters uit de reeks A-Z, 0-9, '.', '-' en '_'.</code_invalid>
  </resourcestrings>
 </xf:instance>
 
 <xf:instance id="validationresults">
  <data xmlns="">
   <field name="code" constraintvalid="true" />
  </data>
 </xf:instance>
 
 <xf:bind nodeset="instance('res')/code_required" relevant="not(exf:required-valid(instance()/cms:entry/cms:code))" />
 <xf:bind nodeset="instance('res')/code_duplicate" relevant="not(exf:constraint-valid(instance()/cms:entry/cms:code))" />
 <xf:bind nodeset="instance('res')/code_invalid" relevant="string-length(instance()/cms:entry/cms:code) &gt; 0 
   and not(exf:schema-valid(instance()/cms:entry/cms:code))" />
</modellogic>

This example contains the following elements:

  • A bind rule on the code field, setting the field required and specifying a type and a constraint rule.
  • An additional value-change handling on the code field, which removes invalid characters from the typed input.
  • A XForms instance element (id="res"), containing (resource) strings.
  • A XForms instance element (id="validationresults"), which is used as target to read and write validation results.
  • Three bind rules which will make sure just one of the alert messages is relevant at the time.

DataEditor xml

The complete version of the adjusted DataEditor xml is shown below.

XML CopyCode image Copy Code
<dataeditor xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns="http://smartsite.nl/namespaces/dataeditor/2.0">
  <layout title="">
    <tabs>
      <tab title="">
        <field name="name" caption="Name">
          <control type="textbox">
            <properties>
              <property name="required">true</property>
              <property name="alert">Naam is verplicht</property>
              <property name="maxlength">50</property>
            </properties>
          </control>
        </field>
        <field name="code">
          <control type="custom">
            <viewdata>
              <xf:input ref="cms:code" appearance="full" maxlength="20" navindex="1" id="cf_code">
                <xf:label>Code
                </xf:label>
                <xf:alert>
                  <xf:output ref="instance('res')/code_required" />
                  <xf:output ref="instance('res')/code_duplicate" />
                  <xf:output ref="instance('res')/code_invalid" />
                </xf:alert>
                <xf:action ev:event="xforms-value-changed">
                  <xf:setvalue ref="instance('validationresults')/field[@name='code']/@constraintvalid" 
                      if="string-length(instance()/cms:entry/cms:code) != 0" 
                      value="choose(string-length(instance()/cms:entry/cms:nr)=0,
                             dataeditor:checkuniqueconstraint('filetypes','code', string(instance()/cms:entry/cms:code)),
                             dataeditor:checkuniqueconstraint('filetypes','code', string(instance()/cms:entry/cms:code), 'nr', string(instance()/cms:entry/cms:nr)))" />
                </xf:action>
              </xf:input>
            </viewdata>
          </control>
        </field>
        <field name="fileextension" caption="FILE_EXTENSION">
          <control type="textbox">
            <properties>
              <property name="required">false</property>
              <property name="maxlength">10</property>
            </properties>
          </control>
        </field>
        <field name="nrmimetype" caption="MIME_TYPE">
          <control type="dropdownlist">
            <itemset ref="is_mimetypes" />
            <properties>
              <property name="required">true</property>
              <property name="alert">U moet een mime-type selecteren.</property>
            </properties>
          </control>
        </field>
      </tab>
    </tabs>
    <modellogic>
      <xf:bind nodeset="cms:entry/cms:code" required="true()" type="dataeditor:genericCodeType" 
               constraint="instance('validationresults')/field[@name='code']/@constraintvalid='true'" />
      <xf:action ev:event="xforms-value-changed" ev:observer="cf_code">
        <xf:setvalue ref="instance()/cms:entry/cms:code" value="fn:upper-case(fn:replace(.,'[^A-Za-z0-9\-\._]',''))" />
      </xf:action>
      <xf:instance id="res">
        <resourcestrings xmlns="">
          <code_required>Code is verplicht. Specificeer een code.</code_required>
          <code_duplicate>Deze code is al in gebruik.</code_duplicate>
          <code_invalid>De opgegeven code is niet geldig. De code moet beginnen met een karakter uit de reeks A-Z of '_', 
            gevolgd door 1 tot 49 karakters uit de reeks A-Z, 0-9, '.', '-' en '_'.</code_invalid>
        </resourcestrings>
      </xf:instance>
      <xf:instance id="validationresults">
        <data xmlns="">
          <field name="code" constraintvalid="true" />
        </data>
      </xf:instance>
      <xf:bind nodeset="instance('res')/code_required" relevant="not(exf:required-valid(instance()/cms:entry/cms:code))" />
      <xf:bind nodeset="instance('res')/code_duplicate" relevant="not(exf:constraint-valid(instance()/cms:entry/cms:code))" />
      <xf:bind nodeset="instance('res')/code_invalid" relevant="string-length(instance()/cms:entry/cms:code) &gt; 0 
          and not(exf:schema-valid(instance()/cms:entry/cms:code))" />
    </modellogic>  
  </layout>
  <itemsets>
    <load tablename="mimetypes" />
  </itemsets>
</dataeditor>

7.9

As of Smartsite 7.9, you can almost forget about the customization described above. To enable an unique constraint check, you just have to add a property to the field. And to provide for context-sensitive alerts, you just have to add two or three specific alert properties. This is explained in the article CheckUniqueConstraint and context-sensitive alerts.