You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bo...@apache.org on 2023/11/14 09:57:02 UTC
(myfaces-tobago) branch tobago-5.x updated: feat(select): Support for noSelectionOptionAttribute of selectItem (#4492)
This is an automated email from the ASF dual-hosted git repository.
bommel pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/tobago-5.x by this push:
new 84a98238dd feat(select): Support for noSelectionOptionAttribute of selectItem (#4492)
84a98238dd is described below
commit 84a98238dd728225821709fdcd092ffac8ac0729
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Tue Nov 14 10:56:57 2023 +0100
feat(select): Support for noSelectionOptionAttribute of selectItem (#4492)
issue: TOBAGO-2257
(cherry picked from commit 93eb26d694cfe19866bb34fb192372befa6d106e)
---
.../renderer/SelectManyCheckboxRenderer.java | 18 ++++---
.../renderkit/renderer/SelectManyListRenderer.java | 4 ++
.../renderkit/renderer/SelectManyRendererBase.java | 3 ++
.../renderkit/renderer/SelectOneListRenderer.java | 5 ++
.../renderkit/renderer/SelectOneRadioRenderer.java | 18 ++++---
.../taglib/component/SelectItemTagDeclaration.java | 9 ++++
.../tobago/internal/util/SelectItemUtils.java | 5 +-
.../apache/myfaces/tobago/model/SelectItem.java | 8 +++
.../myfaces/tobago/renderkit/RendererBase.java | 5 +-
.../SelectManyCheckboxRendererUnitTest.java | 58 ++++++++++++++++++++++
.../renderer/SelectOneChoiceRendererUnitTest.java | 49 ++++++++++++++++++
...ctManyCheckboxNoSelectionOptionNotRendered.html | 29 +++++++++++
...electManyCheckboxNoSelectionOptionRendered.html | 33 ++++++++++++
...electOneChoiceNoSelectionOptionNotRendered.html | 23 +++++++++
.../selectOneChoiceNoSelectionOptionRendered.html | 25 ++++++++++
.../main/webapp/content/030-select/Select.xhtml | 5 +-
16 files changed, 279 insertions(+), 18 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
index 786ca883e4..f8e91f097b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
@@ -74,6 +74,17 @@ public class SelectManyCheckboxRenderer<T extends AbstractUISelectManyCheckbox>
final int[] renderRange = getRenderRangeList(component, reference);
for (final SelectItem item : SelectItemUtils.getItemIterator(facesContext, component)) {
if (renderRange == null || ArrayUtils.contains(renderRange, i)) {
+ final String formattedValue = getFormattedValue(facesContext, component, item.getValue());
+ final boolean checked;
+ if (submittedValues == null) {
+ checked = ArrayUtils.contains(values, item.getValue());
+ } else {
+ checked = ArrayUtils.contains(submittedValues, formattedValue);
+ }
+ if (item.isNoSelectionOption() && required && values != null && values.length > 0 && !checked) {
+ // skip the noSelectionOption if there is another value selected and required
+ continue;
+ }
final boolean itemDisabled = item.isDisabled() || disabled;
final String itemId = id + ComponentUtils.SUB_SEPARATOR + i;
writer.startElement(HtmlElements.DIV);
@@ -86,13 +97,6 @@ public class SelectManyCheckboxRenderer<T extends AbstractUISelectManyCheckbox>
BootstrapClass.FORM_CHECK_INPUT,
BootstrapClass.validationColor(ComponentUtils.getMaximumSeverity(component)));
writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
- final String formattedValue = getFormattedValue(facesContext, component, item.getValue());
- final boolean checked;
- if (submittedValues == null) {
- checked = ArrayUtils.contains(values, item.getValue());
- } else {
- checked = ArrayUtils.contains(submittedValues, formattedValue);
- }
writer.writeAttribute(HtmlAttributes.CHECKED, checked);
writer.writeNameAttribute(id);
writer.writeIdAttribute(itemId);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
index 43d31e80d2..e2e2d99764 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListRenderer.java
@@ -231,6 +231,10 @@ public class SelectManyListRenderer<T extends AbstractUISelectManyList> extends
} else {
contains = ArrayUtils.contains(submittedValues, formattedValue);
}
+ if (item.isNoSelectionOption() && component.isRequired() && values != null && values.length > 0 && !contains) {
+ // skip the noSelectionOption if there is another value selected and required
+ return;
+ }
writer.startElement(HtmlElements.TR);
writer.writeAttribute(DataAttributes.VALUE, formattedValue, true);
writer.writeClassAttribute(
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
index 51f579c7b2..05a6eb0fa9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
@@ -405,6 +405,9 @@ public abstract class SelectManyRendererBase<T extends AbstractUISelectManyBase>
Converter converter = null;
while (converter == null && iterator.hasNext()) {
final SelectItem item = iterator.next();
+ if (item.isNoSelectionOption()) {
+ continue;
+ }
if (item instanceof SelectItemGroup) {
final Iterator<SelectItem> groupIterator = Arrays.asList(
((SelectItemGroup) item).getSelectItems()).iterator();
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
index e6d5b86415..4c8b8d9467 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListRenderer.java
@@ -191,6 +191,7 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
private void encodeSelectItem(FacesContext facesContext, TobagoResponseWriter writer, T component, SelectItem item,
Object value, Object submittedValue, boolean disabled, boolean group) throws IOException {
+
Object itemValue = item.getValue();
// when using selectItem tag with a literal value: use the converted value
if (itemValue instanceof String && value != null && !(value instanceof String)) {
@@ -203,6 +204,10 @@ public class SelectOneListRenderer<T extends AbstractUISelectOneList> extends Se
} else {
contains = value != null && value.equals(itemValue);
}
+ if (item.isNoSelectionOption() && component.isRequired() && value != null && !contains) {
+ // skip the noSelectionOption if there is another value selected and required
+ return;
+ }
writer.startElement(HtmlElements.TR);
writer.writeAttribute(DataAttributes.VALUE, formattedValue, true);
writer.writeClassAttribute(
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
index 648e6ed9d6..daa2ad4bf5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
@@ -124,6 +124,17 @@ public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends
final int[] renderRange = getRenderRangeList(component, reference);
for (final SelectItem item : items) {
if (renderRange == null || ArrayUtils.contains(renderRange, i)) {
+ final String formattedValue = getFormattedValue(facesContext, component, item.getValue());
+ final boolean checked;
+ if (submittedValue == null) {
+ checked = ObjectUtils.equals(item.getValue(), value);
+ } else {
+ checked = ObjectUtils.equals(formattedValue, submittedValue);
+ }
+ if (item.isNoSelectionOption() && component.isRequired() && value != null && !checked) {
+ // skip the noSelectionOption if there is a value available
+ continue;
+ }
final boolean itemDisabled = item.isDisabled() || disabled;
final String itemId = id + ComponentUtils.SUB_SEPARATOR + i;
writer.startElement(HtmlElements.DIV);
@@ -136,13 +147,6 @@ public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends
BootstrapClass.FORM_CHECK_INPUT,
BootstrapClass.validationColor(ComponentUtils.getMaximumSeverity(component)));
writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RADIO);
- final String formattedValue = getFormattedValue(facesContext, component, item.getValue());
- final boolean checked;
- if (submittedValue == null) {
- checked = ObjectUtils.equals(item.getValue(), value);
- } else {
- checked = ObjectUtils.equals(formattedValue, submittedValue);
- }
writer.writeAttribute(HtmlAttributes.CHECKED, checked);
writer.writeNameAttribute(name);
writer.writeIdAttribute(itemId);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectItemTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectItemTagDeclaration.java
index 8820112f7c..b3a2fcfe25 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectItemTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SelectItemTagDeclaration.java
@@ -77,4 +77,13 @@ public interface SelectItemTagDeclaration extends HasBinding, HasId, IsVisual, H
type = "javax.faces.model.SelectItem",
expression = DynamicExpression.VALUE_EXPRESSION_REQUIRED)
void setValue(String value);
+
+ /**
+ * Flag indicating whether the option created
+ * by this component is a noSelectionOption.
+ */
+ @TagAttribute
+ @UIComponentTagAttribute(type = {"boolean"}, defaultValue = "false")
+ void setNoSelectionOption(String itemDisabled);
+
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/SelectItemUtils.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/SelectItemUtils.java
index 89a4180670..6a9e6e629f 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/SelectItemUtils.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/SelectItemUtils.java
@@ -143,7 +143,7 @@ public class SelectItemUtils {
final String description = uiSelectItem.getItemDescription();
final boolean disabled = uiSelectItem.isItemDisabled();
// boolean escape = uiSelectItem.isItemEscaped();
-// boolean noSelectionOption = uiSelectItem.isNoSelectionOption();
+ boolean noSelectionOption = uiSelectItem.isNoSelectionOption();
if (label == null && itemValue != null) {
label = itemValue.toString();
}
@@ -155,7 +155,8 @@ public class SelectItemUtils {
image = tobagoSelectItem.getItemImage();
markup = tobagoSelectItem.getMarkup();
}
- item = new org.apache.myfaces.tobago.model.SelectItem(itemValue, label, description, disabled, image, markup);
+ item = new org.apache.myfaces.tobago.model.SelectItem(itemValue, label, description, disabled,
+ true, noSelectionOption, image, markup);
} else if (!(item instanceof SelectItem)) {
final ValueExpression expression = uiSelectItem.getValueExpression("value");
throw new IllegalArgumentException("ValueExpression '"
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/model/SelectItem.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/SelectItem.java
index 81232ef333..fc40efd23e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/model/SelectItem.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/SelectItem.java
@@ -69,6 +69,14 @@ public class SelectItem extends javax.faces.model.SelectItem implements Visual {
this.markup = markup;
}
+ public SelectItem(
+ final Object value, final String label, final String tip, final boolean disabled, final boolean escape,
+ final boolean noSelectionOption, final String image, final Markup markup) {
+ super(value, label, tip, disabled, escape, noSelectionOption);
+ this.image = image;
+ this.markup = markup;
+ }
+
/**
* Alias name for description.
*/
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
index ac90232324..c870229776 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
@@ -423,7 +423,6 @@ public abstract class RendererBase<T extends UIComponent> extends Renderer {
onlySelected, writer, facesContext);
writer.endElement(HtmlElements.OPTGROUP);
} else {
-
Object itemValue = item.getValue();
// when using selectItem tag with a literal value: use the converted value
if (itemValue instanceof String && values != null && values.length > 0 && !(values[0] instanceof String)) {
@@ -436,6 +435,10 @@ public abstract class RendererBase<T extends UIComponent> extends Renderer {
} else {
contains = ArrayUtils.contains(submittedValues, formattedValue);
}
+ if (item.isNoSelectionOption() && component.isRequired() && values != null && values.length > 0 && !contains) {
+ // skip the noSelectionOption if there is another value selected and required
+ continue;
+ }
if (onlySelected != null) {
if (onlySelected) {
if (!contains) {
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRendererUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRendererUnitTest.java
index 2f3b702550..e045fcae80 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRendererUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRendererUnitTest.java
@@ -75,4 +75,62 @@ public class SelectManyCheckboxRendererUnitTest extends RendererTestBase {
Assertions.assertEquals(loadHtml("renderer/selectManyCheckbox/selectManyCheckboxFatal.html"),
formattedResult());
}
+
+ @Test
+ public void noSelectionOptionRendered() throws IOException {
+ final UISelectManyCheckbox c = (UISelectManyCheckbox) ComponentUtils.createComponent(
+ facesContext, Tags.selectManyCheckbox.componentType(), RendererTypes.SelectManyCheckbox, "id");
+
+ final UISelectItem noSelectionOption = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "noSelectionOption");
+ noSelectionOption.setItemLabel("Choose a value..");
+ noSelectionOption.setNoSelectionOption(true);
+ c.getChildren().add(noSelectionOption);
+ final UISelectItem i1 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i1");
+ i1.setItemLabel("Entry One");
+ i1.setItemValue("Entry One");
+ c.getChildren().add(i1);
+ final UISelectItem i2 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i2");
+ i2.setItemLabel("Entry Two");
+ i2.setItemValue("Entry Two");
+ c.getChildren().add(i2);
+
+ c.encodeAll(facesContext);
+
+ Assertions.assertEquals(
+ loadHtml("renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionRendered.html"),
+ formattedResult());
+ }
+
+ @Test
+ public void noSelectionOptionNotRendered() throws IOException {
+ final UISelectManyCheckbox c = (UISelectManyCheckbox) ComponentUtils.createComponent(
+ facesContext, Tags.selectManyCheckbox.componentType(), RendererTypes.SelectManyCheckbox, "id");
+ c.setValue(new String[] {"Entry One"});
+ c.setRequired(true);
+
+ final UISelectItem noSelectionOption = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "noSelectionOption");
+ noSelectionOption.setItemLabel("Choose a value..");
+ noSelectionOption.setNoSelectionOption(true);
+ c.getChildren().add(noSelectionOption);
+ final UISelectItem i1 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i1");
+ i1.setItemLabel("Entry One");
+ i1.setItemValue("Entry One");
+ c.getChildren().add(i1);
+ final UISelectItem i2 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i2");
+ i2.setItemLabel("Entry Two");
+ i2.setItemValue("Entry Two");
+ c.getChildren().add(i2);
+
+ c.encodeAll(facesContext);
+
+ Assertions.assertEquals(
+ loadHtml("renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionNotRendered.html"),
+ formattedResult());
+ }
}
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRendererUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRendererUnitTest.java
index ca76fa19ef..5a9d27a1eb 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRendererUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRendererUnitTest.java
@@ -51,4 +51,53 @@ public class SelectOneChoiceRendererUnitTest extends RendererTestBase {
Assertions.assertEquals(loadHtml("renderer/selectOneChoice/selectOneChoiceLabel.html"), formattedResult());
}
+ @Test
+ public void noSelectionOptionRendered() throws IOException {
+ final UISelectOneChoice c = (UISelectOneChoice) ComponentUtils.createComponent(
+ facesContext, Tags.selectOneChoice.componentType(), RendererTypes.SelectOneChoice, "id");
+ c.setLabel("label");
+
+ final UISelectItem i1 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i1");
+ i1.setItemLabel("Choose a value..");
+ i1.setItemValue(null);
+ i1.setNoSelectionOption(true);
+ c.getChildren().add(i1);
+ final UISelectItem i2 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i2");
+ i2.setItemLabel("Telecaster");
+ c.getChildren().add(i2);
+
+ c.encodeAll(facesContext);
+
+ Assertions.assertEquals(loadHtml("renderer/selectOneChoice/selectOneChoiceNoSelectionOptionRendered.html"),
+ formattedResult());
+ }
+
+ @Test
+ public void noSelectionOptionNotRendered() throws IOException {
+ final UISelectOneChoice c = (UISelectOneChoice) ComponentUtils.createComponent(
+ facesContext, Tags.selectOneChoice.componentType(), RendererTypes.SelectOneChoice, "id");
+ c.setLabel("label");
+ c.setValue("Telecaster");
+ c.setRequired(true);
+
+ final UISelectItem i1 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i1");
+ i1.setItemLabel("Choose a value..");
+ i1.setItemValue(null);
+ i1.setNoSelectionOption(true);
+ c.getChildren().add(i1);
+ final UISelectItem i2 = (UISelectItem) ComponentUtils.createComponent(
+ facesContext, Tags.selectItem.componentType(), null, "i2");
+ i2.setItemLabel("Telecaster");
+ i2.setItemValue("Telecaster");
+ c.getChildren().add(i2);
+
+ c.encodeAll(facesContext);
+
+ Assertions.assertEquals(loadHtml("renderer/selectOneChoice/selectOneChoiceNoSelectionOptionNotRendered.html"),
+ formattedResult());
+ }
+
}
diff --git a/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionNotRendered.html b/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionNotRendered.html
new file mode 100644
index 0000000000..96a05bee73
--- /dev/null
+++ b/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionNotRendered.html
@@ -0,0 +1,29 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.
+-->
+
+<tobago-select-many-checkbox id='id' class='tobago-auto-spacing tobago-required'>
+ <div>
+ <div class='form-check'>
+ <input class='form-check-input' type='checkbox' checked='checked' name='id' id='id::0' value='Entry One' required='required'>
+ <label class='form-check-label' for='id::0'>Entry One</label>
+ </div>
+ <div class='form-check'>
+ <input class='form-check-input' type='checkbox' name='id' id='id::1' value='Entry Two' required='required'>
+ <label class='form-check-label' for='id::1'>Entry Two</label>
+ </div>
+ </div>
+</tobago-select-many-checkbox>
diff --git a/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionRendered.html b/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionRendered.html
new file mode 100644
index 0000000000..1602eac779
--- /dev/null
+++ b/tobago-core/src/test/resources/renderer/selectManyCheckbox/selectManyCheckboxNoSelectionOptionRendered.html
@@ -0,0 +1,33 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.
+-->
+
+<tobago-select-many-checkbox id='id' class='tobago-auto-spacing'>
+ <div>
+ <div class='form-check'>
+ <input class='form-check-input' type='checkbox' name='id' id='id::0' value=''>
+ <label class='form-check-label' for='id::0'>Choose a value..</label>
+ </div>
+ <div class='form-check'>
+ <input class='form-check-input' type='checkbox' name='id' id='id::1' value='Entry One'>
+ <label class='form-check-label' for='id::1'>Entry One</label>
+ </div>
+ <div class='form-check'>
+ <input class='form-check-input' type='checkbox' name='id' id='id::2' value='Entry Two'>
+ <label class='form-check-label' for='id::2'>Entry Two</label>
+ </div>
+ </div>
+</tobago-select-many-checkbox>
diff --git a/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionNotRendered.html b/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionNotRendered.html
new file mode 100644
index 0000000000..3224545074
--- /dev/null
+++ b/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionNotRendered.html
@@ -0,0 +1,23 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.
+-->
+
+<tobago-select-one-choice id='id' class='tobago-label-container tobago-auto-spacing tobago-required'>
+ <label for='id::field' class='tobago-required col-form-label'>label</label>
+ <select id='id::field' name='id' class='form-select'>
+ <option value='Telecaster' selected='selected'>Telecaster
+ </option></select>
+</tobago-select-one-choice>
diff --git a/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionRendered.html b/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionRendered.html
new file mode 100644
index 0000000000..97e68d5acb
--- /dev/null
+++ b/tobago-core/src/test/resources/renderer/selectOneChoice/selectOneChoiceNoSelectionOptionRendered.html
@@ -0,0 +1,25 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.
+-->
+
+<tobago-select-one-choice id='id' class='tobago-label-container tobago-auto-spacing'>
+ <label for='id::field' class='col-form-label'>label</label>
+ <select id='id::field' name='id' class='form-select'>
+ <option value=''>Choose a value..
+ </option>
+ <option value=''>Telecaster
+ </option></select>
+</tobago-select-one-choice>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/Select.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/Select.xhtml
index 66fe5b1692..0f9b8c8acf 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/Select.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/030-select/Select.xhtml
@@ -20,7 +20,8 @@
<ui:composition template="/main.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:tc="http://myfaces.apache.org/tobago/component"
- xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+ xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+ xmlns:f="http://xmlns.jcp.org/jsf/core">
<p>Tobago provides several ways to select an option.
Entries are added with <code class="language-markup"><tc:selectItem/></code> or
@@ -40,7 +41,9 @@
<tc:section label="Dropdown">
<demo-highlight language="markup"><tc:selectOneChoice label="Dropdown Box"></demo-highlight>
<tc:selectOneChoice label="Dropdown Box">
+ <f:selectItem itemValue="#{null}" itemLabel="--select--" noSelectionOption="true"/>
<tc:selectItems value="#{selectController.entries}"/>
+ <f:ajax render="@this" execute="@this"/>
</tc:selectOneChoice>
</tc:section>