Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Form Questions /

Bug? CheckboxField resets default values


Reply


6 Posts   2676 Views

Avatar
MarijnKampf

Community Member, 164 Posts

5 August 2009 at 4:29am

I've been trying to set a default value for a CheckboxField, however this doesn't seem to behave the same way as TextareaField and Textfield. I've included a basic working sample below copied and pasted from bits from my actual form.

The textarea and textfields show the default value initially. If I change them and submit the form the changed values are shown. If I uncheck CB1 and check CB2 and submit the form they changes are not retained and their values are reset. I would expect them to keep the latest settings as the default value should only be used the first time as with the other two text fields.

Is it just me missing something or should I report this as a bug?

function TheForm() {
   $fields = new FieldSet(
      new TextareaField('Textarea','Area', 8, 3, "Text area test"),
      new CheckboxField('CB1', 'Checked', 1),
      new CheckboxField('CB2', 'Not checked', 0),
      new TextField('TextField', 'Textfield test')
   );
   $actions = new FieldSet(
      new FormAction('ProcessForm', 'Process Form')
   );

   $form = new Form($this, 'MyForm', $fields, $actions, $validator);

   if(is_array(Session::get('MyForm'))) {
      $form->loadDataFrom(Session::get('MyForm'));
   }
   return $form;
}

function ProcessForm($data, $form) {
   Session::set("MyForm", $data);
   return $this->customise($data)->renderWith(array('MyForm', 'Page'));
   // Do form stuff
}

MyForm.ss

$Textarea
$CB1
$CB2
$Textfield
$TheForm

Avatar
Hamish

Community Member, 712 Posts

6 August 2009 at 4:19pm

Edited: 06/08/2009 4:21pm

I haven't tested this, but this is my guess:

If the checkbox is ticked, a value of 'on' will be passed for that field.
If the checkbox is not ticked, no value is passed.

This means that if the checkbox is not ticked, you get no data (so any default will override it), and if the checkbox is ticked, the value is set as 'on', which is invalid.

It is a bit of a flaw in the way 'loadDataFrom' works, so you might have to do something like:

function ProcessForm($data, $form) {

   if(isset($data['CB1']))
      $data['CB1'] = 1;
   else
      $data['CB1'] = 0;

   if(isset($data['CB2']))
      $data['CB2'] = 1;
   else
      $data['CB2'] = 0;

   Session::set("MyForm", $data);
   return $this->customise($data)->renderWith(array('MyForm', 'Page'));
}

Avatar
MarijnKampf

Community Member, 164 Posts

6 August 2009 at 8:06pm

Thanks for posting the workaround Hamish, I'll try it out asap.

But to get a discussion going; shouldn't a CMS framework as SilverStripe handle just this type of exceptions internally? That's one of the points of having a framework isn't it, creating a wrapper for functions so they all behave in a similar. Then a developer doesn't have to manually program exceptions in processing different data types - they all should behave in the same manner with default values that can be passed automatically set.

Avatar
Willr

Forum Moderator, 5513 Posts

6 August 2009 at 8:42pm

If it behaves as you say I would say its a bug but the fix for this would go a bit deeper as like Hamish said. Could you post a complete test file just so I can run through it quickly before you submit a ticket for it.

Avatar
Hamish

Community Member, 712 Posts

7 August 2009 at 3:17pm

Edited: 07/08/2009 3:18pm

Some more info - there is no error in SilverStripe:

Firstly, checkbox fields will pass '1' if they're checked. My tests show that a checked box should load data correctly. Don't know why this isn't the case for you.

Secondly, since unchecked checkboxes will not pass data, set the second argument of loadDataFrom to 'true'. This is a 'clear missing fields' argument that is false by default. Set it to true to clear checkboxes when the variable is not set (ie, the value is unchecked).

$form->loadDataFrom(Session::get('MyForm'), true);

On a side note, I've just found that listboxfields don't populate from dataobject many_many relations loaded this way :(. Might be a patch coming up.

Avatar
Hamish

Community Member, 712 Posts

7 August 2009 at 3:19pm

...or maybe not. Code comments in Form->loadDataFrom:

// We don't actually call the method because it might be slow.
// In a later release, relation methods will just return references to the query that should be executed,
// and so we will be able to safely pass the return value of the
// relation method to the first argument of setValue

*sigh*