/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.tags.form;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.util.TagUtils;

The <option> tag renders a single HTML 'option'. Sets 'selected' as appropriate based on bound value.

Must be used nested inside a SelectTag.

Provides full support for databinding by marking an 'option' as 'selected' if the value matches the value bound to the out SelectTag.

The value property is required and corresponds to the 'value' attribute of the rendered 'option'.

An optional label property can be specified, the value of which corresponds to inner text of the rendered 'option' tag. If no label is specified then the value property will be used when rendering the inner text.

Attribute Summary
Attribute Required? Runtime Expression? Description

cssClass

false

true

HTML Optional Attribute

cssErrorClass

false

true

HTML Optional Attribute. Used when the bound field has errors.

cssStyle

false

true

HTML Optional Attribute

dir

false

true

HTML Standard Attribute

disabled

false

true

HTML Optional Attribute. Setting the value of this attribute to 'true' will disable the HTML element.

htmlEscape

false

true

Enable/disable HTML escaping of rendered values.

id

false

true

HTML Standard Attribute

label

false

true

HTML Optional Attribute

lang

false

true

HTML Standard Attribute

onclick

false

true

HTML Event Attribute

ondblclick

false

true

HTML Event Attribute

onkeydown

false

true

HTML Event Attribute

onkeypress

false

true

HTML Event Attribute

onkeyup

false

true

HTML Event Attribute

onmousedown

false

true

HTML Event Attribute

onmousemove

false

true

HTML Event Attribute

onmouseout

false

true

HTML Event Attribute

onmouseover

false

true

HTML Event Attribute

onmouseup

false

true

HTML Event Attribute

tabindex

false

true

HTML Standard Attribute

title

false

true

HTML Standard Attribute

value

true

true

HTML Optional Attribute

Author:Rob Harrop, Juergen Hoeller
Since:2.0
/** * The {@code <option>} tag renders a single HTML 'option'. Sets 'selected' as * appropriate based on bound value. * * <p><b>Must be used nested inside a {@link SelectTag}.</b> * * <p>Provides full support for databinding by marking an * '{@code option}' as 'selected' if the {@link #setValue value} * matches the value bound to the out {@link SelectTag}. * * <p>The {@link #setValue value} property is required and corresponds to * the '{@code value}' attribute of the rendered '{@code option}'. * * <p>An optional {@link #setLabel label} property can be specified, the * value of which corresponds to inner text of the rendered * '{@code option}' tag. If no {@link #setLabel label} is specified * then the {@link #setValue value} property will be used when rendering * the inner text. * * <p> * <table> * <caption>Attribute Summary</caption> * <thead> * <tr> * <th class="colFirst">Attribute</th> * <th class="colOne">Required?</th> * <th class="colOne">Runtime Expression?</th> * <th class="colLast">Description</th> * </tr> * </thead> * <tbody> * <tr class="altColor"> * <td><p>cssClass</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>cssErrorClass</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute. Used when the bound field has * errors.</p></td> * </tr> * <tr class="altColor"> * <td><p>cssStyle</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>dir</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Standard Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>disabled</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute. Setting the value of this attribute to 'true' * will disable the HTML element.</p></td> * </tr> * <tr class="rowColor"> * <td><p>htmlEscape</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>Enable/disable HTML escaping of rendered values.</p></td> * </tr> * <tr class="altColor"> * <td><p>id</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Standard Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>label</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>lang</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Standard Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>onclick</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>ondblclick</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>onkeydown</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>onkeypress</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>onkeyup</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>onmousedown</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>onmousemove</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>onmouseout</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>onmouseover</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>onmouseup</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Event Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>tabindex</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Standard Attribute</p></td> * </tr> * <tr class="altColor"> * <td><p>title</p></td> * <td><p>false</p></td> * <td><p>true</p></td> * <td><p>HTML Standard Attribute</p></td> * </tr> * <tr class="rowColor"> * <td><p>value</p></td> * <td><p>true</p></td> * <td><p>true</p></td> * <td><p>HTML Optional Attribute</p></td> * </tr> * </tbody> * </table> * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */
@SuppressWarnings("serial") public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
The name of the JSP variable used to expose the value for this tag.
/** * The name of the JSP variable used to expose the value for this tag. */
public static final String VALUE_VARIABLE_NAME = "value";
The name of the JSP variable used to expose the display value for this tag.
/** * The name of the JSP variable used to expose the display value for this tag. */
public static final String DISPLAY_VALUE_VARIABLE_NAME = "displayValue";
The name of the 'selected' attribute.
/** * The name of the '{@code selected}' attribute. */
private static final String SELECTED_ATTRIBUTE = "selected";
The name of the 'value' attribute.
/** * The name of the '{@code value}' attribute. */
private static final String VALUE_ATTRIBUTE = VALUE_VARIABLE_NAME;
The name of the 'disabled' attribute.
/** * The name of the '{@code disabled}' attribute. */
private static final String DISABLED_ATTRIBUTE = "disabled";
The 'value' attribute of the rendered HTML <option> tag.
/** * The 'value' attribute of the rendered HTML {@code <option>} tag. */
@Nullable private Object value;
The text body of the rendered HTML <option> tag.
/** * The text body of the rendered HTML {@code <option>} tag. */
@Nullable private String label; @Nullable private Object oldValue; @Nullable private Object oldDisplayValue; private boolean disabled;
Set the 'value' attribute of the rendered HTML <option> tag.
/** * Set the 'value' attribute of the rendered HTML {@code <option>} tag. */
public void setValue(Object value) { this.value = value; }
Get the 'value' attribute of the rendered HTML <option> tag.
/** * Get the 'value' attribute of the rendered HTML {@code <option>} tag. */
@Nullable protected Object getValue() { return this.value; }
Set the value of the 'disabled' attribute.
/** * Set the value of the '{@code disabled}' attribute. */
public void setDisabled(boolean disabled) { this.disabled = disabled; }
Get the value of the 'disabled' attribute.
/** * Get the value of the '{@code disabled}' attribute. */
protected boolean isDisabled() { return this.disabled; }
Set the text body of the rendered HTML <option> tag.

May be a runtime expression.

/** * Set the text body of the rendered HTML {@code <option>} tag. * <p>May be a runtime expression. */
public void setLabel(String label) { this.label = label; }
Get the text body of the rendered HTML <option> tag.
/** * Get the text body of the rendered HTML {@code <option>} tag. */
@Nullable protected String getLabel() { return this.label; } @Override protected void renderDefaultContent(TagWriter tagWriter) throws JspException { Object value = this.pageContext.getAttribute(VALUE_VARIABLE_NAME); String label = getLabelValue(value); renderOption(value, label, tagWriter); } @Override protected void renderFromBodyContent(BodyContent bodyContent, TagWriter tagWriter) throws JspException { Object value = this.pageContext.getAttribute(VALUE_VARIABLE_NAME); String label = bodyContent.getString(); renderOption(value, label, tagWriter); }
Make sure we are under a 'select' tag before proceeding.
/** * Make sure we are under a '{@code select}' tag before proceeding. */
@Override protected void onWriteTagContent() { assertUnderSelectTag(); } @Override protected void exposeAttributes() throws JspException { Object value = resolveValue(); this.oldValue = this.pageContext.getAttribute(VALUE_VARIABLE_NAME); this.pageContext.setAttribute(VALUE_VARIABLE_NAME, value); this.oldDisplayValue = this.pageContext.getAttribute(DISPLAY_VALUE_VARIABLE_NAME); this.pageContext.setAttribute(DISPLAY_VALUE_VARIABLE_NAME, getDisplayString(value, getBindStatus().getEditor())); } @Override protected BindStatus getBindStatus() { return (BindStatus) this.pageContext.getAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE); } @Override protected void removeAttributes() { if (this.oldValue != null) { this.pageContext.setAttribute(VALUE_ATTRIBUTE, this.oldValue); this.oldValue = null; } else { this.pageContext.removeAttribute(VALUE_VARIABLE_NAME); } if (this.oldDisplayValue != null) { this.pageContext.setAttribute(DISPLAY_VALUE_VARIABLE_NAME, this.oldDisplayValue); this.oldDisplayValue = null; } else { this.pageContext.removeAttribute(DISPLAY_VALUE_VARIABLE_NAME); } } private void renderOption(Object value, String label, TagWriter tagWriter) throws JspException { tagWriter.startTag("option"); writeOptionalAttribute(tagWriter, "id", resolveId()); writeOptionalAttributes(tagWriter); String renderedValue = getDisplayString(value, getBindStatus().getEditor()); renderedValue = processFieldValue(getSelectTag().getName(), renderedValue, "option"); tagWriter.writeAttribute(VALUE_ATTRIBUTE, renderedValue); if (isSelected(value)) { tagWriter.writeAttribute(SELECTED_ATTRIBUTE, SELECTED_ATTRIBUTE); } if (isDisabled()) { tagWriter.writeAttribute(DISABLED_ATTRIBUTE, "disabled"); } tagWriter.appendValue(label); tagWriter.endTag(); } @Override protected String autogenerateId() throws JspException { return null; }
Return the value of the label for this 'option' element.

If the label property is set then the resolved value of that property is used, otherwise the value of the resolvedValue argument is used.

/** * Return the value of the label for this '{@code option}' element. * <p>If the {@link #setLabel label} property is set then the resolved value * of that property is used, otherwise the value of the {@code resolvedValue} * argument is used. */
private String getLabelValue(Object resolvedValue) throws JspException { String label = getLabel(); Object labelObj = (label == null ? resolvedValue : evaluate("label", label)); return getDisplayString(labelObj, getBindStatus().getEditor()); } private void assertUnderSelectTag() { TagUtils.assertHasAncestorOfType(this, SelectTag.class, "option", "select"); } private SelectTag getSelectTag() { return (SelectTag) findAncestorWithClass(this, SelectTag.class); } private boolean isSelected(Object resolvedValue) { return SelectedValueComparator.isSelected(getBindStatus(), resolvedValue); } @Nullable private Object resolveValue() throws JspException { return evaluate(VALUE_VARIABLE_NAME, getValue()); } }