Website demonstration: Checkboxes - current and previous state
Sources
Explanation
The issue is with checkboxes is that the is not input for then when the user unchecks them. This class can be used to record which checkboxes are being displayed and whether they are unchecked or not.
It is useful when you want to know if the checkbox state has just changed.
It also generates to value to be assigned to the checkbox in the html.
How it works:
- It holds a list of all the checkboxes and their state (checked or not) by position.
- This current state vector is an array or characters that is stored in a hidden field on the form.
- Each checkbox is assigned a value based on the position in the list.
There are various details created for each checkbox based on the key (cbxDetails):
- The label to use in the html - (cbxLabel)
The value to be used in the html - (cbxValue)_
The key of the details - _(key)
whether the checkbox state has changed - (hasChanged)
- the current state - (curChecked)
- the previous state - (prvChecked)
These details are also available via the array iterator - (getIterator)
Processing:
Build form:
- create a new CheckboxHistory($cbxValueList)
Generate the checkboxes using
When form is input, assume $_POST is used:
- generate a new CheckboxHistory($cbxValueList)
- if there is $_POST['cbxInputs'] then apply it - _(fromCheckedList($POST['cbxInputs']))
- apply the state of all the checkboxes from the hidden field - _(fromCbxStateString($POST['cbxAllStates'])
All done
Code that looks after the Checkboxes List
// look after the checkbox states
$cbxHistory = new CheckboxHistory($vars);
if (isset($_POST['allBoxes'])) {
if (isset($_POST['allBoxes']['cbxChecked'])) {
$cbxHistory->fromCheckedList($_POST['allBoxes']['cbxChecked']);
}
$cbxHistory->fromCbxStateString($_POST['allBoxes']['history']);
}
// extract arrays for testing
$extract1 = array();
$extract2 = array();
$extract3 = array();
$cbxIter = $cbxHistory->getIterator();
for ($i = 0; $i <= 8; $i++) { // extract first 9 entries
$extract1[] = $cbxIter->current();
$cbxIter->next();
}
for ($i = 0; $i <= 12; $i++) { // extract next 12 entries
$extract2[] = $cbxIter->current();
$cbxIter->next();
}
while ($cbxIter->valid()) { // extract remaining entries
$extract3[] = $cbxIter->current();
$cbxIter->next();
}
The class that maintains the checkboxes state
<?php // http://stackoverflow.com/questions/36849297/variable-to-specific-parts-of-array
/**
* Maintain a list of checkboxes and the immidiate history
*
* Uses: array of $key => $label
*
* the key can be numbers or string the class works with keys
*
* e.g. $cbxHistory = new CheckboxHistory(array('key1' => 'label 1',
* 'key2' => 'label 2',
* 'key3' => 'label 3',
* ))
*
* It uses a string to hold whether each checkbox in the list currently is checked or not
*
* e.g. $cbxHistory->cbxStateString()
*
* This will be stored in a hidden field $_POST and will become the $prvCheckedState
*
*
*
* It generates all the details to
* 1) use in the checkbox HTML
* 'label' is for the html checkbox label
* 'value' is for the html checkbox value
* note: the value is a position in the list not a key!
*
* 2) The state of the checkbox and whether is has just changed
*
* e.g. $cbxHistory->cbxDetails($key);
*
* returns: array('label' => $this->cbxLabel($key),
* 'value' => $this->cbxValue($key),
* 'key' => $key,
*
* 'hasChanged' => $this->hasChanged($key),
* 'curChecked' => $this->curChecked($key),
* 'prvChecked' => $this->prvChecked($key));
*
* It uses a cbxStateString to know what the previous states of the checkbox
*
* e.g. $cbxHistory->fronCbxCheckedState($oldCbxCheckedState);
*
* This will normally be from the html 'hidden' cbxState field
*
*/
class CheckboxHistory {
protected $valueList = null;
protected $curCheckedState = '';
protected $prvCheckedState = '';
protected $keyList = null; // needed to find the position of the key
public function __construct(array $valueList, $prvStateStr = '')
{
$this->valueList = $valueList;
$this->curCheckedState = str_repeat('0', count($this->valueList));
$this->prvCheckedState = str_repeat('0', count($this->valueList));
$this->keyList = array_keys($valueList);
if (!empty($prvStateStr)) {
$this->fromCbxStateString($prvStateStr);
}
}
/**
* The label value to be used in the html
*
* @param mixed $key
*
* @return label text
*/
public function cbxLabel($key)
{
return $this->valueList[$key];
}
/**
* The value to be used for the checkbox in the html.
*
* It is actually the postion of the lookup key in the list
*
* @param mixed $key
*
* @return integer
*/
public function cbxValue($key)
{
return $this->keyToPosition($key);
}
/**
* This is the current state vector of all the checkboxes
*
* It is stored in a 'hidden' field on the form
*
* It is used in the fromCbxStateString() method
*
* @return string
*/
public function cbxStateString()
{
return $this->curCheckedState;
}
/**
* All the details (checkbox state) in one convenient list
*
* @param mixed $key
*
* @return array
*/
public function cbxDetails($key)
{
return array('label' => $this->cbxLabel($key),
'value' => $this->cbxValue($key),
'key' => $key,
'hasChanged' => $this->hasChanged($key),
'curChecked' => $this->curChecked($key),
'prvChecked' => $this->prvChecked($key),
);
}
/**
* All the cbxDetails as an iterator
*
* @return \ArrayIterator
*/
public function getIterator()
{
$details = array();
foreach($this->keyList as $key) {
$details[] = $this->cbxDetails($key);
}
return new \ArrayIterator($details);
}
/**
* Set or unset a checkbox by key value
*
* @param mixed $key
* @param boolean $checked
*
* @return void
*/
public function setCheckbox($key, $checked = true)
{
$keyPos = $this->keyToPosition($key);
$this->curCheckedState[$keyPos] = $checked ? '1' : '0';
}
/**
* current state of a checkbox
*
* @param mixed $key
*
* @return boolean
*/
public function curChecked($key)
{
$keyPos = $this->keyToPosition($key);
return (bool) $this->curCheckedState[$keyPos];
}
/**
* previous state of a checkbox
*
* @param mixed $key
*
* @return booleam
*/
public function prvChecked($key)
{
$keyPos = $this->keyToPosition($key);
return (bool) $this->prvCheckedState[$keyPos];
}
/**
* Has the checkbox changed state (user checked or unchecked it)
*
* @param mixed $key
*
* @return boolean
*/
public function hasChanged($key)
{
$keyPos = $this->keyToPosition($key);
return $this->curCheckedState[$keyPos] !== $this->prvCheckedState[$keyPos];
}
/**
* set the curCheckedState from an array of values ($positions)
*
* @param array $positionList i.e. $_POST
*
* @return void
*/
public function fromCheckedList(array $checkedPos)
{
$this->curCheckedState = str_repeat('0', count($this->valueList));
foreach ($checkedPos as $position) {
$this->setCheckbox($this->keyList[$position], true);
}
}
/**
* This is the previous state of the all checkboxes
*
* It is obtained from the chechboxes 'hidden' field
*
* @param string $prvStateStr
*
* @return void
*/
public function fromCbxStateString($prvStateStr)
{
// must be the correct lentgth
$this->prvCheckedState = str_pad($prvStateStr, count($this->valueList), $this->prvCheckedState);
}
// given a key get the postion of the key in the list
protected function keyToPosition($key)
{
return array_search($key, $this->keyList);
}
}
die('<pre>'.print_r($_POST['ck'], true).'</pre>');at the start of your PHP script. On the frontend, if you only checked one checkbox then only that value would be sent to the server. Based on what you are saying, all of the checkboxes are checked on the frontend.name="ck[]"on the frontend, only the checked boxes are being sent to the backend as an auto-numbered (incremental) array. If on the frontend you check off boxes 34, 35, and 36 then PHP receives$_POST['ck'][0] = "value of 34"; $_POST['ck'][1] = "value of 35"; $_POST['ck'][2] = "value of 36";