#26265: RendererMixin id_for_label causes HTML id uniqueness violation
----------------------------+--------------------
     Reporter:  scoenye     |      Owner:  nobody
         Type:  Bug         |     Status:  new
    Component:  Forms       |    Version:  1.9
     Severity:  Normal      |   Keywords:
 Triage Stage:  Unreviewed  |  Has patch:  0
Easy pickings:  0           |      UI/UX:  0
----------------------------+--------------------
 When rendering a ChoiceField RadioSelect widget using form.as_p, the
 result is

 {{{
 <ul id="id_field-field">
   <li><label for="id_field-field_0">
       <input id="id_field-field_0" type="radio" value="1" name="field-
 field">
       ...
       </label>
   </li>
   <li><label for="id_field-field_1">...
   </li>
   ...
 </ul>
 }}}

 Note that the id attribute of the ul element is id_field-field

 When rendering the same RadioSelect field manually using
 {{{
 <ul id="{{field.id_for_label}}">
   {% for choice in field %}
     <li><label for="{{ choice.id_for_label }}">{{ choice.tag }}</li>
   {% endfor %}
 </ul>
 }}}
 the result is
 {{{
 <ul id="id_field-field_0">
   <li><label for="id_field-field_0">
         <input id="id_field-field_0" type="radio" value="1" name="field-
 field">
         </label>
   </li>
   <li>...
   ...
 </ul>
 }}}

 The outer ul element id now has the same id as the first radio button.
 This should not be.

 The problem is caused by the implementation of id_for_label in
 forms.widgets.RendererMixin
 {{{
 def id_for_label(self, id_):
         # Widgets using this RendererMixin are made of a collection of
         # subwidgets, each with their own <label>, and distinct ID.
         # The IDs are made distinct by y "_X" suffix, where X is the zero-
 based
         # index of the choice field. Thus, the label for the main widget
 should
         # reference the first subwidget, hence the "_0" suffix.
         if id_:
             id_ += '_0'
         return id_
 }}}
 vs. what widgets.ChoiceFieldRenderer.render() does:
 {{{
 id_ = self.attrs.get('id')
 ...
 return format_html(self.outer_html,
                            id_attr=format_html(' id="{}"', id_) if id_
 else '',
                            content=mark_safe('\n'.join(output)))
 }}}
 The docs
 
[https://docs.djangoproject.com/en/1.9/ref/forms/widgets/#django.forms.RadioSelect]
 state
   The outer <ul> container will receive the id attribute defined on the
 widget.
 which makes me believe render() is correct. Either way, I think these
 should be consistent with each other. If not, then the docs should mention
 using the "name" attribute to avoid the id collision.

--
Ticket URL: <https://code.djangoproject.com/ticket/26265>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.c5c5819b09fc5f5c39d2c546ee192047%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to