Dynamicky generovaný formulář – vzdálenosti – dělám to správně

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
motorcb
Člen | 552
+
0
-

Zdravim.

Pokouším se o jednoduchý dynamicky generovaný formulář pro zadávání vzdálenosti mezi městy (matice a * a). Měst bude dynamický počet.
Cenik

Dělám to takto: definice zdrojových dat. Matice měst a vzdáleností:

$this->array = array();
$this->array["Praha"]["Praha"] = "X";
$this->array["Praha"]["Bratislava"] = 330;
$this->array["Praha"]["Rim"] = 1320;
$this->array["Bratislava"]["Praha"] = 330;
$this->array["Bratislava"]["Bratislava"] = "X";
$this->array["Bratislava"]["Rim"] = 100;
$this->array["Rim"]["Praha"] = 1320;
$this->array["Rim"]["Bratislava"] = 100;
$this->array["Rim"]["Rim"] = "X";

$this->template->array = $this->array;//odeslu do sablony

Vytvoření komponent pro formulář:

protected function createComponentPriceForm()
{
    $form = new Form;

    foreach ( $this->array as $rowNameFrom => $row )
    {
        foreach ( $row as $rowNameTo => $rowCelText )
        {
            $form->addText( "distance_" . $rowNameFrom . "_" . $rowNameTo, 'Vzdalenost' )
                    ->setValue( $rowCelText );
        }
    }

    $form->addSubmit( 'send', 'Upravit ceník' );

    $form->onSuccess[] = $this->priceFormSucceeded;
    return $form;
}

public function priceFormSucceeded( $form )
{
    $values = $form->getValues();
    dump( $values );
}

Kde skládám název textboxu: distance_odkud_kam

Šablona:

{form priceForm}
    <table>
        <tr>
            <th>Město</th>
            {foreach $array as $key => $header}
                <th>{$key}</th>
            {/foreach}
        </tr>
        {foreach $array as $rowNameFrom => $row}
            <tr>
                <th>{$rowNameFrom}</th>
                {foreach $row as $rowNameTo => $rowCelText}
                    <td>
                        {*{$rowNameFrom}-{$rowNameTo} = {$rowCelText}<br/>*}
                        {input distance_{$rowNameFrom}_{$rowNameTo}}
                    </td>
                {/foreach}
            </tr>
        {/foreach}
    </table>
    {input send}
{/form priceForm}

Po odeslání formuláře bych rozparsroval jednotlivé textboxy ze kterých zjistím město odkud, kam a novou vzdálenost.

Je mé řešení korektní, nebo existuje elegantnější způsob?

Díky

s4muel
Člen | 92
+
0
-

ja by som skusil asi nejako takto:

public function createComponentPriceForm() {
    $cities = array(
        'ba' => 'bratislava',
        'bb' => 'banska bystrica',
        'ke' => 'kosice',
        //...
    );
    //+ matica vzdialenosti, napr:
    $distance['ba']['bb'] = 10;
    $distance['bb']['ke'] = 20;
    //...

    $form = new Nette\Application\UI\Form;
    //mesta v riadkoch
    foreach($cities as $city_from_short => $city_from_full) {
        //vytvorenie nazvu premennej pre pod-formular (moze byt cokolvek, len unikatne. bude pouzite nizsie_
        $subform_variable_name = 'sf_' . $city_from_short;
        //vytvorenie noveho pod-formulara (containera)
        $$subform_variable_name = $form->addContainer($city_from_short);
        //mesta v stlpcoch
        foreach($cities as $city_to_short => $city_to_full) {
            //ak je mesto rozdielne, tak pridaj normalny povoleny input do sub-formulara
            if($city_to_short != $city_from_short) {
                $$subform_variable_name->addText($city_to_short, $city_to_full);
                //+ nastavenie default hodnoty podla potreby
            }
            //inak (ak je mesto v riadku a stlpci rovnake) disabluj input
            else {
                $$subform_variable_name->addText($city_to_short, $city_to_full)->setDisabled();
            }
        }
    }
    $form->addSubmit('submit');
    $form->onSuccess[] = $this->priceFormSubmitted;
    return $form;
}

potom budes mat vysledky nasledovne a nemusis ich parsovat:

Nette\ArrayHash #375e
ba => Nette\ArrayHash #eca9
   bb => "50" (2)
   ke => "100" (3)
bb => Nette\ArrayHash #8113
   ba => "50" (2)
   ke => "50" (2)
ke => Nette\ArrayHash #1fa5
   ba => "100" (3)
   bb => "50" (2)

Editoval s4muel (18. 1. 2014 23:23)

motorcb
Člen | 552
+
0
-

@s4muel:
Díky, to vypadá zajímavě. A jak vypíšu textboxy do matice?
matice

s4muel
Člen | 92
+
0
-

no neviem, ci najidealnejsie, ale skus takto:
treba dostat do template pole s mestami: v createComponentPriceForm() factory by malo stacit

$this->template->cities = $cities;

a potom v latte:

{form priceForm}
    <table>
        <tr>
            <th>mesto</th>
            {*vypiseme nazvy miest do hlavicky tabulky*}
            <th n:foreach="$cities as $city_full">{$city_full}</th>
        </tr>
        {*neviem, ako inak ziskat vsetky sub-formulare, tak iterujem cez vsetky formularove komponenty,
        mozno poradi niekto nieco lepsie*}
        {foreach $form->components as $component}
            {*pokracujem len ak je component triedy form\container (sub-formular) a ked sa jeho nazov nachadza v poli s mestami (a teda nie je to nejaky iny sub-formular)*}
            {if $component instanceof \Nette\Forms\Container && array_key_exists($component->name, $cities)}
                <tr>
                    {*$component->name je napr 'ba' a preto do prveho stlpca vypiseme $cities['ba'] atd...*}
                    <th>{$cities[$component->name]}</th>
                    {*iterujeme cez controls sub-formulara tohto cyklu a vypiseme jeho podradene componenty/mesta *}
                    <td n:foreach="$component->controls as $item">{$item->control}</td>
                </tr>
            {/if}
        {/foreach}
    </table>
    {input submit}
{/form priceForm}
ddx
Člen | 2
+
0
-

Díky za tuhle diskusi, tvořím něco docela podobného a vaše příklady mi dost pomohly. *thumbs up*