Checkbox u každého prvku vytaženého z databáze

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

Ahoj,

řeším takový problém, se kterým si moc nevím v Nette rady. Vytahuji z databáze záznamy a vypisuji je na stránku (jedná se o příchozí zprávy, stejně jako v emailu). Potřebuji ke každé zprávě přidat checkbox, abych mohl následně doplnit funkcionality jako „Smazat vybrané“, „Přesunout vybrané do archivu“ apod.

Jak to udělat co nejefektivněji? Konkrétněji – nevím si rady s tím, jak vytvořit ke každému vytaženému záznamu ten checkbox. Záznamy vytahuji v metodě render, formulář tvořím přes komponenty.

Děkuji za tipy.

srigi
Nette Blogger | 558
+
0
-

Formular mozes v tovarnicke vytvarat plne dynamicky. Budem vychadzat z toho, ze kazda sprava ma nejaky perex a ID. Metodu render nebude treba, lebo perex sa vlozi do formulara.

Presenter

class BlablablaPresenter extends Presenter
{
  protected function createComponentFormNews($name)
  {
    $form = new AppForm($this, $name);
    $form->addGroup('Newsky');

    $news = Model::getAll();
    foreach ($news as $newie) {
        $form->addCheckbox('newie-' . $newie->id, $newie->perex);
    }

    $form->addGroup('Akce');
    $form->addSelect('action', 'Akce:', array('Smazat', 'Archivovat', 'Skryt'));
    $form->addSubmit('dowork', 'Vykonat');
    $form->onSubmit[] = ($this, 'SubmittedFormNews');
    return $form;
  }

  // spracovanie
  public function SubmittedFormNews(AppForm $form)
  {
    ... $form->values; // spracovanie
    ...
    $this->redirect('Blablbla:'); // po spracovani nezabudnut na redirect!
  }
}

Bolo by asi vhodne prehodit label a checkbox vo formulari, aby to vyzeralo k svetu. to bude vyzadovat cca taketo sablony:

templates/Blablabla.default.phtml

{block #content}

  {include '@formNews.phtml', form=>$presenter['formNews']}

templates/@formNews.phtml

{control $form begin}
  <!-- hidden fields -->
  <div n:foreach="$form->getComponents(TRUE, 'Nette\Forms\HiddenField') as $control">{$control->control}</div>

  <!-- errors -->
  {assign errors => $form->errors}
  <ul class="error" n:if="$errors" n:block="#errors">
    <li n:foreach="$errors as $error">{$error}</li>
  </ul>

  <!-- groups -->
  <fieldset n:foreach="$form->groups as $group" n:if="$group->controls && $group->getOption('visual')" n:block="#group">
    <legend n:ifset="$group->options['label']">{$group->options['label']}</legend>
    <p n:ifset="$group->options['description']">{$group->options['description']}</p>

    <table n:block="#controls">
      <tr {attr class('required', $control->getOption('required'))} n:foreach="$group->controls as $control" n:if="!$control->getOption('rendered')" n:block="#pair">
        <td n:block="#control">{!$control->control}{if $control instanceof Checkbox}{!$control->label}{/if}</td>
        <td n:block="#label">{if $control instanceof Button || $control instanceof Checkbox}&nbsp;{else}{!$control->label}{/if}</td>
      </tr>
    </table>
  </fieldset>

  <!-- non-group -->
  {include #controls, group => $form}

{control $form end}

Ta tovarnicka ti vytvori kopec checkboxov s menami newie-ID, takze v callbacku na spracovanie si pekne preiterujes cez zaskrtnute checkboxy a z ich mien pomocou PHP funkcii na pracu so stringami vytiahnes ID. Potom uz iba v modeli vykonas akciu nad tymi IDckami.

Jakub
Člen | 30
+
0
-

Díky za vyčerpávající odpověď, ještě se zeptám – mám nyní v tom rendru také stránkování + ten dotaz na DB je docela složitý (tzn. nevypisuji u zpráv jen perex, ale zhruba 5 informací u každé zprávy). I v takovém případě nebudu ten render již potřebovat? Mám to stránkování dát také do té komponenty formuláře? A jak vypíšu ty další údaje o zprávě?

Děkuji za pomoc!

srigi
Nette Blogger | 558
+
0
-

Jakub napsal(a):

mám nyní v tom rendru také stránkování + ten dotaz na DB je docela složitý (tzn. nevypisuji u zpráv jen perex, ale zhruba 5 informací u každé zprávy). I v takovém případě nebudu ten render již potřebovat? Mám to stránkování dát také do té komponenty formuláře? A jak vypíšu ty další údaje o zprávě?

Ano render sa zrusi cely, lebo cela ta obrazovka bude v podstate formular (okrem paginatora). Takze v tovarnicke sa z DB vytiahnu tie newsky, ktore maju byt prave zobrazene. Troska som sa hral v MockFlow, pripravil som wireframe aby to slo lepsie predstavit

Riadok s checkboxom je jeden form pair (tj. form label & form control) a do labelu sa natrepu vsetky tie infozz. Treba sa pohrat s jeho HTML kodom. V tom foreach cykle v tovarnicke sa vykona cca toto:

foreach ($news as $newie) {
  $div = Html::el();
  $div->create('strong', $newie->perex);
  $subject = Html::el('span')->class(array('subject'))->setText($newie->subject);
  $date = Html::el('span')->class(array('date'))->setText($newie->date);
  $div->add($subject);
  $div->add($date);

  $form->addCheckbox('newie-' . $newie->id, $div);
}

Do labelu forulara by sa tak malo vyrenderovat nieco ako

<td class"label"><div><strong>text perex</strong><span class="subject">text subject</span><span class="date">15.6.2010</span></div></td>

treba ale trocha upravit tu custom sablonu formulara, vyhladaj riadok

<td n:block="#label">{if $control instanceof Button || $control instanceof Checkbox}&nbsp;{else}{!$control->label}{/if}</td>

a vymaz ten if (aby sa HTML elementy „dostali k slovu“)

<td n:block="#label">{!$control->label}</td>

K tomu paginovaniu – s uspechom mozes v tovarnicke na zaciatku pouzivat konstrukciu

$page = ($this->getParam('page')) ? (int) $this->getParam('page') : 1;

Pomocou toho si z DB vytiahnes konktretnu „stranku“ (LIMIT, OFFSET) s novinkami a zostavis formular. Na renderovanie potom pouzi VisualPaginator (takze tu metodu render nakoniec budes potrebovat :D)

Pisal som to z hlavy, takze to nemusi fungovat hned na prvykrat!

Editoval srigi (8. 3. 2010 11:25)

Jakub
Člen | 30
+
0
-

Super, díky! Poslední dotaz – Chystám se ke zprávám přidat ještě další formulář pro jejich filtrování. Mohl bys, prosím, naznačit, jakým způsobem bys toto řešil, když zprávy tahám v té komponentě formuláře? Začínám se do toho zamotávat..

Mockrát děkuji!

srigi
Nette Blogger | 558
+
0
-

Jakub napsal(a):

Super, díky! Poslední dotaz – Chystám se ke zprávám přidat ještě další formulář pro jejich filtrování. Mohl bys, prosím, naznačit, jakým způsobem bys toto řešil, když zprávy tahám v té komponentě formuláře? Začínám se do toho zamotávat..

Mockrát děkuji!

Hmm, toto si uz neviem predstavit (funkcnost). Skus pomocou toho MockFlow nakreslit wireframe aby bolo jasne ake ma to filtrovanie fungovat. Alebo to popis slovami.

Jakub
Člen | 30
+
0
-

Mělo by to fungovat následovně: Nad tabulkou se zprávami bude jednoduchý formulář – v základní verzi třeba jen s jedním inputem, který bude sloužit k filtrování zpráv podle předmětu. Tzn. když budu chtít najít všechny zprávy, které obsahují v předmětu slovo „Nette“, napíšu do inputu Nette a kliknu na hledej – ve výsledku dostanu vyfiltrované zprávy, které mají v předmětu tento řetězec.

Díky!

srigi
Nette Blogger | 558
+
0
-

Premyslal som nad tym – toto je jasny pripad, kde sa pouziju signaly. Komponente posles signal s parametrom (String: ‚Nette‘) a ten na jeho zaklade vygeneruje objekt AppForm a ten vrati. Nova komponenta by tak mala dedit od AppForm a iba ju rozsiris o metodu na prijimanie tohto signalu.

Toto si to vyziada trocha prekopat predchadzajuci kod – komponenta sa bude musiet presunut do vlastneho suboru – v Presenteri sa uz nebude vytvarat objek formu ako doteraz:

protected function createComponentFormNews($name)
{
  $form = new AppForm($this, $name);
  ...
  return $form;
}

ale sa presunie do toho potomka AppForm. Takze ta tovarnicka v Presenteri sa prekope asi takto

Presenter

protected function createComponentNews($name)
{
  return new NewsControl($this, $name);
}

a prida sa subor s definiciou komponenty:

components/NewsControl.php

class NewsControl extends AppForm
{
  // obsluha signalu
  public function handleFilternews($input)
  {
    $news = Model::getByFilter($input);
    foreach ($news as $newie) {
      ...
      $this->addCheckbox('newie-' . $newie->id, $newie->perex); // podedili sme od AppForm, takze $this
    }

    $this->addGroup('Akce');
    ...
    return $this;
  }
}

cca takto. Len kua neviem ako nadefinovat callback na spracovanie formu – skus sa pozriet na dokundamentaciu. Popr. si to naprogramuj a skusaj ten callback vseliako definovat. Bude traba tiez nejako nadefinovat to ze klepnutie na „Hledaj/Filtruj“ posle formu signal na horeuvedny handler.

Editoval srigi (9. 3. 2010 17:15)

Jakub
Člen | 30
+
0
-

Díky moc za cenné rady! Našel jsem při procházení fóra ještě tohle: https://componette.org/search/?…, což v podstatě absolutně řeší můj problém :) Vědět to dřív, tak tady neotravuju..

Nicméně stejně děkuji za pomoc, zkoušel jsem i dle tvého návodu a alespoň jsem se zase něco nového naučil.