Jump to content
Juergen

Best way to deal with multiple checkboxes in module configuration

Recommended Posts

Hello @ all,

On a custom inputfield  I want to use a multiple checkbox field (InputfieldCheckboxes) in the inputfield configuration. The user can select which fields of this inputfield are required.

Screenshot(3).png.478e4066ff1a4f4c4f8decb3813d2577.png

I have created these checkboxes as followed: As you can see, I am not using "InputfieldCheckbox" but "InputfieldCheckboxes" (the multi-checkbox version)

$f = $this->modules->get('InputfieldCheckboxes');
              $f->label = _x('Required fields', 'simpleaddress');
              $options = [
                'street' => _x('Street', 'simpleaddress'),
                'number' => _x('Number', 'simpleaddress'),
                'postalcode' => _x('Postalcode', 'simpleaddress'),
                'city' => _x('City', 'simpleaddress'),
                'state' => _x('State', 'simpleaddress'),
                'country' => _x('Country', 'simpleaddress'),
              ];
              foreach($options as $value => $label) {
                $f->attr('name', 'input_required[]');              
                $checked = ($this->input_required == '1') ? 'checked' : '';//How to check if a checkbox was checked???????
                $f->addOption($value, $label, ['checked' => $checked]);
              }
              $inputfields->append($f);

Problem:

I am struggeling to find out how to determine if a checkbox was checked or not . On a single checkbox field I can use something like this to set the checked attribute.

$f->attr('checked', $this->myInputfield == '1' ? 'checked' : '');

How can I achive the same for a multiple checkbox field? I haven´t found a working example.

Thanks in advance!

Share this post


Link to post
Share on other sites

2020-06-27_112933.png.09f9e99a64c3b83b5f063e118fa7c129.png

/** @var InputfieldCheckboxes $f */
$f = $modules->get('InputfieldCheckboxes');
$f->name = 'foo';
$f->label = 'Foo';
$f->addOptions([
	'red' => 'Red',
	'green' => 'Green',
	'blue' => 'Blue',
]);
// The value will be an array e.g. ['red', 'blue']
$f->value = $this->foo;
$inputfields->add($f);

 

  • Like 4

Share this post


Link to post
Share on other sites

Thanks for your help @Robin S

Your code:

11 hours ago, Robin S said:

/** @var InputfieldCheckboxes $f */ $f = $modules->get('InputfieldCheckboxes'); $f->name = 'foo'; $f->label = 'Foo'; $f->addOptions([ 'red' => 'Red', 'green' => 'Green', 'blue' => 'Blue', ]); // The value will be an array e.g. ['red', 'blue'] $f->value = $this->foo; $inputfields->add($f);

Unfortunately $this->foo is always empty after form submission (independent if a checkbox was marked or not).

Array
(
    [0] => 
)

By taking a look at the $this object you can see that you cannot reach the foo property via $this->foo, because foo is part of the field object.

ProcessWire\InputfieldSimpleAddress Object
(
    [data] => Array
        (
            [input_street] => 
            [input_number] => 
            [input_postalcode] => 
            [input_city] => 
            [input_state] => 
            [input_country] => test
            [label] => Address
            [description] => 
            [icon] => 
            [notes] => 
            [detail] => 
            [head] => 
            [required] => 0
            [requiredIf] => 
            [collapsed] => 0
            [showIf] => 
            [columnWidth] => 
            [skipLabel] => 
            [wrapClass] => 
            [headerClass] => 
            [contentClass] => 
            [textFormat] => 4
            [renderValueFlags] => 0
            [prependMarkup] => 
            [appendMarkup] => 
            [hasFieldtype] => ProcessWire\FieldtypeSimpleAddress Object
                (
                )

            [hasField] => ProcessWire\Field Object
                (
                    [id] => 116
                    [name] => address
                    [label] => Address
                    [flags] => 
                    [type] => ProcessWire\FieldtypeSimpleAddress Object
                        (
                        )

                    [data] => Array
                        (
                            [label1021] => Adresse
                            [collapsed] => 0
                            [foo] => Array
                                (
                                    [0] => red
                                    [1] => green
                                    [2] => blue
                                )

                        )

                )

            [hasPage] => ProcessWire\Page Object
                (
                    [id] => 1
                    [name] => home
                    [parent] => 
                    [status] => systemID
                    [template] => home
                    [numChildren] => 3
                    [title] => Home
                    [data] => Array
                        (
                            [title] => Home
                        )

                )

        )

)

I have checked all 3 checkboxes and you get the values (red, green and blue) in the object as part of the data property (see code below):

[data] => Array
                        (
                            [label1021] => Adresse
                            [collapsed] => 0
                            [foo] => Array
                                (
                                    [0] => red
                                    [1] => green
                                    [2] => blue
                                )

                        )

Therefore you can get the values (array) only by using

$this->hasField->data['foo']

instead of

$this->foo

My goal:

I want to make multiple checkboxes stay checked after form submission if they were marked by an user. I havent found a way to achive this at the moment and this was the reason for this post.

 

Share this post


Link to post
Share on other sites

I found a solution to keep multiple checkboxes checked after form submission.

Here is the complete code of this multiple checkbox list field:

// checkbox field to make specific fields required
          $f = $this->modules->get('InputfieldCheckboxes');
          $f->label = _x('Required fields', 'simpleaddress');
          $f->attr('name', 'input_required');
          $options = [
            'street' => _x('Street', 'simpleaddress'),
            'number' => _x('Number', 'simpleaddress'),
            'postalcode' => _x('Postalcode', 'simpleaddress'),
            'city' => _x('City', 'simpleaddress'),
            'state' => _x('State', 'simpleaddress'),
            'country' => _x('Country', 'simpleaddress'),
          ];
          $values = (isset($this->hasField->data['input_required'])) ? $this->hasField->data['input_required'] : [];
          foreach($options as $value => $label) {
            $checked = (in_array($value,$values)) ? 'checked' : '';
            $f->addOption($value, $label, ['checked' => $checked]);
          }
          $f->description = _x('If checked the input is required.', 'simpleaddress');
          $inputfields->append($f);

Lets take a closer look:

$values = (isset($this->hasField->data['input_required'])) ? $this->hasField->data['input_required'] : [];

This is how we get all checked checkboxes after form submission. "input_required" is the name attribute of my multiple checkbox field. If one or more checkboxes were checked, we get the values in an array, otherwise we will get an empty array.

So $values could be an empty array or an array with values like ['street, postalcode'].

To make the checkboxes checked after form submission we include a simple check inside the foreach loop.

$checked = (in_array($value,$values)) ? 'checked' : '';

We check if the value from the foreach loop is in the array too. If yes, then add the checked attribute as third parameter to this checkbox input.

$f->addOption($value, $label, ['checked' => $checked]);

Thats all! Maybe someone has a nicer solution, please post it here.

Best regards

Share this post


Link to post
Share on other sites
14 hours ago, Juergen said:

Therefore you can get the values (array) only by using


$this->hasField->data['foo']

instead of


$this->foo

Well, this depends on if the stored value for the inputfield has been set as a property of the class. There are multiple different places you might use an inputfield and it's up to you to get the value you want to set to it. How you get it doesn't have anything to with InputfieldCheckboxes per se - you just need to make sure you are setting an array as the value.

If the inputfield is used in the getModuleConfigInputfields() method of a module then the value stored in the module config is automatically set as a property of the module class.

Alternatively, if you have a config field for an Inputfield module (in the getConfigInputfields() method) that is used with a PW field then this config data is stored on the field, because only the field has a record in the database. In other words there is a "fields" table but no "inputfields" table. So you can get the stored value from the $field object as you are doing, but arguably it's better to make use of the features that PW has built in to automatically populate Inputfield properties from the corresponding Field. The Field class has this code in the getInputfield() method:

// custom field settings
foreach($this->data as $key => $value) {
	if($inputfield instanceof InputfieldWrapper) {
		$has = $inputfield->hasSetting($key) || $inputfield->hasAttribute($key);
	} else {
		$has = $inputfield->has($key);
	}
	if($has) {
		if(is_array($this->trackGets)) $this->trackGets($key); 
		$inputfield->set($key, $value); 
	}
}

What this boils down to is:

"For every data property set on this Field object, check to see if a property of that name exists on the Inputfield object used by this field. If it does, set the value stored on this Field object as a property of the Inputfield object".

So to make use of this you just need to set a property name in your Inputfield module's init() method, so that the property can be seen to exist when Field::getInputfield() is called. And typically you would set a default value for this property when appropriate. You can see how this is done in InputfieldRadios for example:

public function init() {
	$this->set('optionColumns', 0); 
	parent::init();
}

By doing this:

1. A default value of 0 is set for optionColumns

2. Any value for optionColumns that is stored on a corresponding Field object automatically becomes available in the InputfieldRadios class as $this->optionColumns.

  • Like 3

Share this post


Link to post
Share on other sites

Wow, thanks for this detailed explanation!! Things are getting clearer now for me!!!

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...