Může CheckboxList vracet associativní pole místo indexového?

FilipDolezal
Člen | 9
+
0
-

Dobrý den, snažím se přepsat chování checkboxlistu tak, aby místo indexového pole vracelo asociativní.

Například CheckboxList, který je vytvořen takto:

$arr = [
	"po" => "Pondělí",
	"ut" => "Úterý",
	...
]
$form->addCheckboxList("dny", "Vyber dny", $arr)

Po zaškrtnutí např.: po, st, a ct
vrátí indexové pole vybraných polí:

array (3)
0 => 'po'
1 => 'st'
2 => 'ct'

Jak docílit, aby mi po odeslání formuláře přišlo associativní pole?

array (7)
po => true
ut => false
st => true
ct => true
pa => false
...

Děkuji

Polki
Člen | 553
+
0
-

Ve vychozim stavu tusim ne, ale muzes si udelat vlastni ktery to umi

Pepino
Člen | 249
+
-1
-

@FilipDolezal můžeš použít něco jako:

array_walk($arr, fn(&$item, $key, $values) => $item = in_array($key, $values), $values);
netteman
Člen | 122
+
0
-

Prohlížeč nezaškrtnuté položky CheckboxListu ani neodešle

Editoval netteman (11. 5. 2022 14:14)

Bulldog
Člen | 110
+
+2
-

@Pepino Zbytečně složité. Tvoje složitost je O(n2) Daleko lepší řešení je toto:
nadefinování pole, které bude pro výběr v checkBoxListu: (původní autorovo)

$arr = [
	"po" => "Pondělí",
	"ut" => "Úterý",
	...
]
$form->addCheckboxList("dny", "Vyber dny", $arr);

Příprava návratové hodnoty

$resultArr = array_map(fn($item) => false, $arr);	// array_map => kdo ví, jestli s původním nebude chtít ještě něco dělat.

Doplnění návratové hodnoty o vybraná pole

foreach ($values->dny as $den) {
	$resultArr[$den] = true;
}

Sice se o trochu více napíšeš, ale vzhledem k tomu, že to napíšeš jednou a pak už jen používáš komponentu(input), tak o 3 řádky navíc ti neublíží a vykoupí tě složitostí O(n)

@netteman To na to, co chce tazatel snad nemá vůbec vliv ne? Mu stačí jen ty hodnoty, které jsou zaškrtnuté. Výsledné pole si z nich pak dokáže sestavit viz výše.

Editoval Bulldog (11. 5. 2022 17:07)

FilipDolezal
Člen | 9
+
0
-

@Bulldog toto řešení mi dává největší smysl. Doufal jsem, že se mi podaří přepsat chování checkboxlistu a ne zpracování vrácené hodnoty, ale vaše řešení není vůbec dlouhé ani složité. Děkuji

Editoval FilipDolezal (11. 5. 2022 17:18)

Bulldog
Člen | 110
+
+2
-

@FilipDolezal Upravit výchozí chování samozřejmě můžeš… :) Třeba takto:

class CheckboxListAssoc extends Nette\Forms\Controls\CheckboxList
{
    private array $items;

    public function __construct($label = null, array $items = null)
    {
        parent::__construct($label, $items);
        $this->items = $items ?? [];
    }

    public function getValue(): array
    {
        $selectedDays = parent::getValue();
        $items = array_map(fn($item) => false, $this->items);
        foreach ($selectedDays as $selectedDay) {
            $items[$selectedDay] = true;
        }
        return $items;
    }
}

class Form extends Nette\Application\UI\Form
{
    public function addCheckboxListAssoc(string $name, string $label = null, array $items = null): CheckboxListAssoc
    {
        return $this[$name] = new CheckboxListAssoc($label, $items);
    }
}

a v aplikaci pak už budeš místo Nette\Application\UI\Form používat tento tvůj Form.

Takže reálně když si to zkusíš takto:

public function createComponentForm(): Form
{
    $form = new Form();

    $arr = [
        'po' => 'Pondělí',
        'ut' => 'Úterý',
        'st' => 'Středa',
        'ct' => 'Čtvrtek',
        'pa' => 'Pátek',
    ];

    $form->addCheckboxListAssoc('dny', 'Vyber dny', $arr);

    $form->addSubmit('submit', 'Odeslat');

    $form->onSuccess[] = function (Form $form) {
        bdump($form->getValues());
    };

    return $form;
}

Tak ti dump bude házet výsledky přesně takové, jaké chceš. :)
Samozřejmě se hodí přetížit ještě metody setValue, setDefaultValue, getRawValue atp., podle použití.

Editoval Bulldog (11. 5. 2022 17:59)

Polki
Člen | 553
+
+1
-

@Bulldog Ještě jsi zapomněl zmínit, že pokud používá nad formulářem i funkci addContainer, tak musí podědit i tu, aby container uměl funkci addCheckboxListAssoc.

Na to je nejlepší pak použít traitu, která tuto metodu bude přidávat a tuto použít jak ve formuláři, tak v containeru