We have moved to Github. Please open tickets there.

Opened 5 years ago

Closed 2 years ago

#397 closed Defect (fixed)

Settings code does not handle checkboxes (and presumably radio buttons)

Reported by: marcus Owned by:
Priority: normal Milestone: Elgg 1.8.0
Component: UI/UX Version: 1.7
Severity: major Keywords:
Cc: brettp, evan.b.winslow@… Difficulty: easy

Description (last modified by marcus)

Seems to be a problem only with checkboxes.

Two problems:

1) Values are set to string "Array"
2) Because unset checkboxes are not passed at all, unchecked single options are unchecked

Attachments (1)

supress-hidden-field.patch (1.5 KB) - added by danielwells 3 years ago.
Possible patch to suppress hidden field

Download all attachments as: .zip

Change History (19)

comment:1 Changed 5 years ago by marcus

  • Description modified (diff)
  • Priority changed from major to minor

comment:2 Changed 4 years ago by twall

The following code block inserts hidden input fields for checkboxes if they are unchecked, as well as submitting the checkbox value as a single value instead of an array. To use this as a patch, use extend_view() on 'widgets/editwrapper'.

Maybe the original intention of using an array was to somehow work around variables not being passed when unchecked, but I can't see how it can work as written.

<?php
/** Ensure unchecked variables have a default setting. */
$guid = $vars['entity']->getGUID();
?>
<script type='text/javascript'>
  $(document).ready(function() {
      var guid = '<?php echo $guid; ?>';
      var form = $('#widgetform'+guid);
      var checkboxes = $(':checkbox', form);
      var add_hidden = function(checkbox) {
        var el = $('<input type="hidden" />');
        var name = $(checkbox).attr('name');
        el.attr('id', name.replace(/[^a-zA-Z0-9_]/g,"_"));
        el.attr('name', name.replace('[]',''));
        el.val(0);
        el.appendTo(form);
      };
      checkboxes.each(function() {
          $(this).attr('name', $(this).attr('name').replace('[]',''));
          if (!$(this).attr('checked')) {
            add_hidden(this);
          }
        });
      checkboxes.click(function () {
          if ($(this).attr('checked')) {
            $('#' + $(this).attr('name').replace(/[^a-zA-Z0-9_]/g,"_")).remove();
          }
          else {
            add_hidden(this);
          }
        });
    });

</script>


comment:3 Changed 4 years ago by brettp

I just discovered and documented this bug in the plugin tutorial on the docs site.

A solution is to use the pulldown input type instead of a checkbox or radio box. This makes things ugly, but at least functional.

A better solution would be in actions/plugins/settings/save.php to wipe all plugin settings before saving the new set. This runs into a problem of when plugin authors use (misuse?) plugin settings for internal, non-admin changeable settings.

comment:4 Changed 3 years ago by brettp

  • Component set to API
  • Resolution set to wontfix
  • Status changed from new to closed
  • Type changed from unconfirmed defect to confirmed defect

I don't see how this can be fixed without JS, which I am reluctant to include in the default view for checkbox and radio inputs. Unless someone has a good idea, I'm closing this as wontfix. Also, that's a pretty horrible idea, 12-months-ago-Brett.

comment:5 Changed 3 years ago by cash

  • Component changed from API to Core
  • Milestone set to Elgg 1.7.2
  • Priority changed from normal to high
  • Resolution wontfix deleted
  • Severity changed from minor to major
  • Status changed from closed to reopened
  • Version set to 1.7

This definitely needs to be fixed and the only way is through javascript. Other frameworks do it this way.

comment:6 follow-up: Changed 3 years ago by cash

15 minute ago Cash is wrong. Here is a non-javascript solution:

<input type="hidden" name="params[<name>]" value="0" />
<input type="checkbox" name="params[<name>]" value="1" <?php echo $checked; ?> />

If the checkbox is selected, it overrides the hidden value. Thoughts?

comment:7 Changed 3 years ago by twall

I had that thought initially, but I don't think you're guaranteed that one option will override the other, and you might actually end up passing *both* options. I vaguely recall testing this and finding no concrete answer.

comment:8 Changed 3 years ago by cash

You will *never* get both options. Every now and then someone reports not getting an array in this situation as a bug to the php developers and they close the ticket with "bogus" status. To get an array, you have to use name[].

Browsers send the form data in the order that it appears (I believe the RFC specifies this). PHP processes the form data from start to end by default. Variables that appear later in a form should overwrite earlier variables.

http://us2.php.net/manual/en/ini.core.php#ini.request-order

My testing has so far confirmed this.

comment:10 in reply to: ↑ 6 Changed 3 years ago by brettp

Cash's proposed solution in #6 sounds awesome if we can confirm it works across multiple browsers and servers. Since other platforms use it, that's a very good indication that it's the way to go.

comment:11 Changed 3 years ago by cash

Web servers tested

  • Apache 2

Browsers tested

  • IE7
  • Chrome
  • Firefox
  • Opera

I'll upload a plugin that tests this for others to use.

comment:12 Changed 3 years ago by ewinslow

  • Cc evan.b.winslow@… added

comment:13 Changed 3 years ago by brettp

  • Resolution set to fixed
  • Status changed from reopened to closed

(In [svn:6541]) Fixes #397: Added hidden value for checkboxes to allow use in settings. Cleaned up checkboxes code.

comment:14 Changed 3 years ago by brettp

  • Difficulty set to easy
  • Milestone changed from Elgg 1.7.2 to Elgg 1.8
  • Priority changed from high to normal
  • Resolution fixed deleted
  • Status changed from closed to reopened

I've had problems with the current implementation so am reopening this as a reminder. Passing a single option to the checkbox shouldn't append []s to the name.

comment:15 Changed 3 years ago by cash

  • Component changed from Core to UI/UX

comment:16 Changed 3 years ago by danielwells

The hidden value breaks code in instances where the checkboxes view is called multiple time to build the list of checkboxes (in my case a nested select to display both main categories and their sub categories). In these cases multiple hidden values are intermixed between the real options and break up the potential array.

Possible solution: add flag to view where a developer can suppress the creation of the hidden value. In my case I would not set the flag the first time I call the view but would call it each subsequent time.

comment:17 Changed 3 years ago by danielwells

In the above comment I meant to say "nested for loop" and not "nested select"

Changed 3 years ago by danielwells

Possible patch to suppress hidden field

comment:18 Changed 2 years ago by cash

  • Resolution set to fixed
  • Status changed from reopened to closed

(In [svn:7424]) Fixes #397 and Refs #2396 Can suppress the default value for both input/checkbox and input/checkboxes

Note: See TracTickets for help on using tickets.