Search

I'm wondering how to go about specifying that an option is selected for a select menu. The markup for my front end entry event field looks something like this:

<label>Type
  <select name="fields[type]">
    <option value="Intro">Intro</option>
    <option value="Section">Section</option>
    <option value="Subsection">Subsection</option>
    <option value="Subsubsection">Subsubsection</option>
    <option value="Body">Body</option>
    <option value="Appendix">Appendix</option>
    <option value="Line Items">Line Items</option>
  </select>
</label>

How would I go about applying an attribute of selected="selected" to the appropriate option? I had thought about calling a template:

<xsl:template name="content-type-options">
  <xsl:param name="options">
    <select>
      <option>Intro</option>
      <option>Section</option>
      <option>Subsection</option>
      <option>Subsubsection</option>
      <option>Body</option>
      <option>Appendix</option>
      <option>Line Items</option>
    </select>
  </xsl:param>
  <xsl:for-each select="$options/select/option">
    <option value="{.}">
      <xsl:if test="type/item = .">
        <xsl:attribute name="selected">selected</xsl:attribute>
      </xsl:if>
      <xsl:value-of select="name"/>
    </option>
  </xsl:for-each>
</xsl:template>

But, of course, this results in an XSLT processing error:

XSLTProcessor::transformToXml(): Invalid type

because the $options parameter is treating the XML elements as a text string and not XML nodes.

Any ideas?

I ran into a similar problem a while back with a select box that was populated with US states. I ended up creating a static XML data source with every state and then looping through each state comparing it to what I had on record. The following was my solution

  <div class="select state">
    <label>
    <xsl:if test="//errors/error[@field = 'state']">
      <xsl:attribute name="class">error</xsl:attribute>
    </xsl:if>
    State
    <select name="fields[state]">
      <option value=""></option>
    <xsl:for-each select="//states/state">
    <xsl:choose>
        <xsl:when test="/data/events/members-cs/member/field[@handle = 'state' ] = . ">
            <option value="{.}" selected="selected"><xsl:value-of select="." /></option>
        </xsl:when> 
        <xsl:otherwise>
            <option value="{.}"><xsl:value-of select="." /></option>            
        </xsl:otherwise>
    </xsl:choose>   
    </xsl:for-each>
    </select>
    </label>
  </div>

Thanks, Lewis. I was trying to figure out how to do it without having to attach an additional XML data source. So, I worked out how to build the XML from a list of comma separated values using TestXSLT. Here's my CSV to XML template:

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:output method='html' version='1.0' encoding='utf-8' indent='no'/>

<xsl:param name="csv">
  Intro, Section, Subsection, Subsubsection, Body, Appendix, Line Items
</xsl:param>

<xsl:template match="/">
  <xsl:param name="selected" select="'Section'"/>
  <xsl:param name="options">
    <xsl:call-template name="options">
      <xsl:with-param name="input" select="$csv"/>
    </xsl:call-template>
  </xsl:param>
  <xsl:for-each select="$options/option">
    <option value="{.}">
      <xsl:if test=". = $selected">
        <xsl:attribute name="selected">selected</xsl:attribute>
      </xsl:if>
      <xsl:value-of select="."/>
    </option>
  </xsl:for-each>
</xsl:template>

<xsl:template name="options">
  <xsl:param name="input"/>
  <xsl:param name="value" select="normalize-space(substring-before($input,','))"/>
  <xsl:param name="remaining-values" select="normalize-space(substring-after($input,','))"/>
  <xsl:if test="$remaining-values != ''">
    <xsl:element name="option">
      <xsl:value-of select="$value"/>
    </xsl:element>
    <xsl:text>
</xsl:text>
    <xsl:call-template name="options">
      <xsl:with-param name="input" select="$remaining-values"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

Creative :-)

For whatever reason, this worked in TextXSLT but not in Symphony. Symphony does not appear to recognize $options as a node set. Here's what I ended up with as a workaround to actually creating the XML:

<xsl:template name="content-type-options">
  <xsl:param name="csv" select="'Intro, Section, Subsection'"/>
  <xsl:param name="selected" select="'Body'"/>
  <xsl:param name="options">
    <xsl:call-template name="option-values">
      <xsl:with-param name="input" select="$csv"/>
      <xsl:with-param name="selected" select="$selected"/>
    </xsl:call-template>
  </xsl:param>
  <xsl:copy-of select="$options"/>
</xsl:template>

<xsl:template name="option-values">
  <xsl:param name="selected" select="'Section'"/>
  <xsl:param name="input"/>
  <xsl:param name="value">
    <xsl:choose>
      <xsl:when test="contains($input,',')">
        <xsl:value-of select="normalize-space(substring-before($input,','))"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="normalize-space($input)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:param>
  <xsl:param name="remaining-values" select="normalize-space(substring-after($input,','))"/>
  <option value="{$value}">
    <xsl:if test="$value = $selected">
      <xsl:attribute name="selected">selected</xsl:attribute>
    </xsl:if>
    <xsl:value-of select="$value"/>
  </option>
  <xsl:if test="$remaining-values != ''">
    <xsl:call-template name="option-values">
      <xsl:with-param name="input" select="$remaining-values"/>
      <xsl:with-param name="selected" select="$selected"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

Thankfully, this works. (Updated: found a bug where the list was truncated by one item.)

dynamic population from extension would be ideal….

I don’t know if it will help, but I’ve been using comma to element templates for a while and have a few that work. As an example here is my comma-to-options template, it is passed a comma separated list of values and a matching comma separated list of display terms. A selected value can also be passed which will set the appropriate option as (you guessed it) selected. It also has an option just to pass a value of max if you want a numbered drop down say for a quantity field, any way here it is.

<xsl:template name="comma_to_options">
    <xsl:param name="values" select="''"/>
    <xsl:param name="displays" select="''"/>
    <xsl:param name="max" select="''"/>
    <xsl:param name="count" select="1"/>
    <xsl:param name="selected" select="''"/>
    <xsl:variable name="value">
        <xsl:choose>
            <xsl:when test="$max!=''">
                <xsl:value-of select="$count"/>
            </xsl:when>
            <xsl:when test="contains($values,',')">
                <xsl:value-of select="normalize-space(substring-before($values, ','))"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="normalize-space($values)"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:variable name="display">
        <xsl:choose>
            <xsl:when test="$max!=''">
                <xsl:value-of select="$count"/>
            </xsl:when>
            <xsl:when test="contains($displays,',')">
                <xsl:value-of select="normalize-space(substring-before($displays, ','))"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="normalize-space($displays)"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:variable name="whole_values" select="substring-after($values, ',')"/>
    <xsl:variable name="whole_displays" select="substring-after($displays, ',')"/>
    <option value="{$value}">
        <xsl:if test="$value=$selected">
            <xsl:attribute name="selected">
                <xsl:text>selected</xsl:text>
            </xsl:attribute>
        </xsl:if>
        <xsl:value-of select="$display"/>
    </option>
    <xsl:choose>
        <xsl:when test="$max!=''">
            <xsl:if test="$count&lt;$max">
                <xsl:call-template name="comma_to_options">
                    <xsl:with-param name="max" select="$max"/>
                    <xsl:with-param name="count" select="$count+1"/>
                    <xsl:with-param name="selected" select="$selected"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:when>
        <xsl:otherwise>
            <xsl:if test="$whole_values!='' and $whole_displays!=''">
                <xsl:call-template name="comma_to_options">
                    <xsl:with-param name="values" select="$whole_values"/>
                    <xsl:with-param name="displays" select="$whole_displays"/>
                    <xsl:with-param name="selected" select="$selected"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

I also have comma-to-radio, comma-to-checkboxs and comma-to-inputs as well if it helps.

Form Controls? ;-)

Form Controls used to accept comma-delimeted values but I dropped it in favour of XML-only to keep things clean.

So can you use Form Controls to highlight a select box value that had been selected in the backend and have it highlighted in a form on the front end where I am trying to edit an entry?

EDIT Bascially, any help in using the Selected option from the section entry in front end form using form controls would be greatly appreciated.

OK so I'm trying and that's the main thing:

<xsl:call-template name="form:label">
         <xsl:with-param name="for" select="'Department'"/>
         <xsl:with-param name="text" select="department-name"/>
         <xsl:with-param name="child">
           <xsl:call-template name="form:select">
            <xsl:with-param name="handle" select="'department'"/>


            <xsl:with-param name="options">      
<xsl:for-each select="/data/departments/entry">

                    <option value="{@id}"><xsl:if test="/data/departments/entry/@id = '/data/jobs/entry/department/item/@id'">
        <xsl:attribute name="selected">
            <xsl:text>selected</xsl:text>
        </xsl:attribute>
    </xsl:if><xsl:value-of select="department-name"/></option>
                    </xsl:for-each>

            </xsl:with-param>
           </xsl:call-template>
         </xsl:with-param>
         </xsl:call-template>

Any ideas what's not working here? Doesn't seem to populate the required selection from my section. I'm trying to marry up the ID of the Entry in the section with the select box link ID and place the attribute "selected" on the value that has been previously chosen from within the admin area.. anyone got any pointers?

EDIT

It's cool. Solved it without Form Controls.. as I need to do some Datasource chaining as well:

<xsl:variable name="dept" select="/data/jobs/entry/department/item/@id"/>
<xsl:for-each select="/data/departments/entry">
            <option value="{@id}">
    <xsl:if test="@id = $dept">
                <xsl:attribute name="selected">
                    <xsl:text>selected</xsl:text>
                </xsl:attribute>
            </xsl:if>

    <xsl:value-of select="department-name"/></option>
      </xsl:for-each>

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details