[development] Fwd: Creating embedded unordered lists of checkboxes

David Metzler metzlerd at metzlerd.com
Fri Jan 15 07:07:14 UTC 2010


It is quite possible that I don't understand properly what you're  
trying to do, but I think a slightly different approach is warranted,  
because you'll have a hard time getting the nesting to work since  
your children array is only going to be one level deep, and  
drupal_render is always going to wrap your checkboxes in form item  
div tags (I think).

Option 1 Storing a hierarchical array of values in #options and  
render the items in a bulleted list using theme_checkbox() calls in  
your custom theme. Just return the rendered text rather than walking  
the #children array.  This is more akin to the first approach in the  
document that I sent you, only running bulleted lists instead of  
using theme_table.  This assumes you want a flat array back and not a  
hierarchy of values.

Option 2 would be to  think about implementing a custom form element  
and writing your own expand (or process in D7) function.  The expand  
function would build the right hierarchy with appropriate #tree=TRUE  
and theme functions for the individual checkboxes theme_li_checkbox  
maybe and theme_ul_checkbox  to build the checkbox array correctly.  
See the expand_checboxes (d6) for a better example of how #options  
gets converted to child elements.

Hope one of these approaches helps.

Dave





On Jan 14, 2010, at 10:21 AM, Steve Edwards wrote:

> I figured out the problem with the custom checkboxes theme function  
> and drupal_render.  Basically, drupal_render is assuming that I  
> will render all of the children checkboxes in my custom theme  
> function, so it doesn't do it itself.  I just took the code from  
> drupal_render and modified it slightly, and my children checkboxes  
> are rendered:
>
>   // Code from drupal_render()
>   $children = element_children($element);
>   foreach ($children as $key) {
>     $content .= drupal_render($element[$key]);
>   }
>
>   $element['#children'] = $content;
>
> However, now I have another problem, and that is that the #title  
> and #description values are being displayed twice.  Stepping  
> through the code shows that two theme functions are being called  
> twice: theme_checkboxes in form.inc AND my custom theme checkboxes  
> function.  What I don't understand is why, since I explicitly  
> defined a theme function for my checkboxes form element in my form  
> definition:
>
>   $form['site_sections'] = array(
>     '#type' => 'checkboxes',
>     '#title' => t('Site Sections'),
>     '#options' => $options,
>     '#description' => t('Test description'),
>     '#theme' => 'section_permissions_checkboxes',
>   );
>
> This is even further demonstrated by looking at the rendered HTML  
> for the form.
>
> <form id="section-permissions-admin-form" method="post" accept- 
> charset="UTF-8" action="/user/6/section_permissions">
> <div>
> <div class="form-item">
> <label>Site Sections: </label>
> <div class="form-checkboxes">
> <div class="form-item">
> <label>Site Sections: </label>
> <div class="form-checkboxes">
> <div id="edit-site-sections-917-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-918-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-923-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-924-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-925-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-926-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-927-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-928-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-919-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-929-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-930-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-931-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-932-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-920-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-933-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-934-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-921-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-935-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-936-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-937-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-938-wrapper" class="form-item">
> </div>
> <div id="edit-site-sections-922-wrapper" class="form-item">
> </div>
> </div>
> <div class="description">Test description</div>
> </div>
> </div>
> <div class="description">Test description</div>
> </div>
>
> Can anyone explain why this is happening?
>
> Thanks.
>
> Steve
>
>
> Begin forwarded message:
>
>> From: Steve Edwards <killshot91 at gmail.com>
>> Date: January 14, 2010 7:36:41 AM PST
>> To: development at drupal.org
>> Subject: Re: [development] Creating embedded unordered lists of  
>> checkboxes
>>
>> Well, the problem with that is I've tried just that (creating my  
>> own custom checkboxes function), and as I said in the initial  
>> post, when it gets to my custom theme_checkboxes form, the  
>> #children have not been rendered since that step was skipped in  
>> drupal_render() simply because #theme was set for the checkboxes  
>> element.  If I could get to my custom theme_checkboxes element  
>> with $element['#children'] set, I'd be fine, but that's what's  
>> throwing the wrench into things.
>>
>> Thanks.
>>
>> Steve
>>
>>
>>
>> On Jan 13, 2010, at 7:39 PM, David Metzler wrote:
>>
>>> I think you're on the right track.  Check out:
>>>
>>> http://drupal.org/node/197578
>>>
>>> which shows you how to render  a checkboxes control into a  
>>> table.    You shouldn't technically need the form-item theme  
>>> function to do what you're doing, but rather just a custom  
>>> checkboxes theming form.   I've done that successfully in D5, but  
>>> it looks like it would work in D6.  Note the direct calls to  
>>> theme_checkbox in that function so that it renders each of the  
>>> checkboxes properly
>>>
>>> Hope that helps,
>>>
>>> Dave
>>>
>>>
>>>
>>> On Jan 13, 2010, at 4:54 PM, Steve Edwards wrote:
>>>
>>>> I have a need to create a two-level unordered list of checkboxes  
>>>> from a two level taxonomy vocabulary.  So for instance, if my  
>>>> vocabulary is
>>>>
>>>> - Level 1 term 1
>>>> -- Level 2 term 1
>>>> -- Level 2 term 2
>>>> -- Level 2 term 3
>>>> - Level 1 term 2
>>>> -- Level 2 term 4
>>>> -- Level 2 term 5
>>>> - Level 1 term 3
>>>>
>>>> I want to create the following:
>>>>
>>>> <ul>
>>>> <li><input type = checkbox">Level 1 term 1</li>
>>>> <ul>
>>>>  <li><input type = checkbox">.Level 2 term 1</li>
>>>>  <li><input type = checkbox">Level 2 term 2</li>
>>>>  <li><input type = checkbox">Level 2 term 3</li>
>>>> </ul>
>>>> <li><input type = checkbox">Level 1 term 2</li>
>>>> <ul>
>>>>  <li><input type = checkbox">Level 2 term 4</li>
>>>>  <li><input type = checkbox">Level 2 term 5</li>
>>>> <ul>
>>>> <li><input type = checkbox">Level 1 term 3<li>
>>>> </ul>
>>>>
>>>> What is the best way to do this?  Just use a checkboxes element  
>>>> type and create my own theme function for the form?  Modify  
>>>> something like theme_item_list?  Or is there a better (and  
>>>> easier) way that I'm missing?
>>>>
>>>> What I tried doing was to create a theme function for my  
>>>> checkboxes element by setting the #theme property for the  
>>>> element to my custom theme function (and registering the  
>>>> function in hook_theme).  I then just made a copy of  
>>>> theme_checkboxes() (and theme_form_element since it's called  
>>>> from theme_form_checkboxes) and renamed to match hook_theme and  
>>>> the #theme property.  However, when doing that, none of my  
>>>> checkboxes are rendered at all.  On stepping through the code, I  
>>>> found the problem in drupal_render starting at line 2868:
>>>>
>>>> if (!isset($elements['#children'])) {
>>>>   $children = element_children($elements);
>>>>   // Render all the children that use a theme function.
>>>>   if (isset($elements['#theme']) && empty($elements 
>>>> ['#theme_used'])) {
>>>>     $elements['#theme_used'] = TRUE;
>>>>
>>>>     $previous = array();
>>>>     foreach (array('#value', '#type', '#prefix', '#suffix') as  
>>>> $key) {
>>>>       $previous[$key] = isset($elements[$key]) ? $elements 
>>>> [$key] : NULL;
>>>>     }
>>>>     // If we rendered a single element, then we will skip the  
>>>> renderer.
>>>>     if (empty($children)) {
>>>>       $elements['#printed'] = TRUE;
>>>>     }
>>>>     else {
>>>>       $elements['#value'] = '';
>>>>     }
>>>>     $elements['#type'] = 'markup';
>>>>
>>>>     unset($elements['#prefix'], $elements['#suffix']);
>>>>     $content = theme($elements['#theme'], $elements);
>>>>
>>>>     foreach (array('#value', '#type', '#prefix', '#suffix') as  
>>>> $key) {
>>>>       $elements[$key] = isset($previous[$key]) ? $previous 
>>>> [$key] : NULL;
>>>>     }
>>>>   }
>>>>   // Render each of the children using drupal_render and  
>>>> concatenate them.
>>>>   if (!isset($content) || $content === '') {
>>>>     foreach ($children as $key) {
>>>>       $content .= drupal_render($elements[$key]);
>>>>     }
>>>>   }
>>>> }
>>>>
>>>> So basically, because I have #theme set for the checkboxes  
>>>> field, it skips the rendering of the individual checkbox  
>>>> elements.  To me, it makes sense that I override the theme  
>>>> function for the checkboxes type since that's the element type,  
>>>> but that doesn't seem to be the case.  So what do I need to do  
>>>> to be able to simply theme my checkboxes element?
>>>>
>>>> Thanks.
>>>>
>>>> Steve
>>>>
>>>
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.drupal.org/pipermail/development/attachments/20100114/543698a7/attachment-0001.html 


More information about the development mailing list