Formulář v šabloně s datagridem

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

Ahoj,

nevím si už rady, co vyzkoušet nebo jak vyřešit můj problém.

Zkoušel jsem nette verze 0.9.2, 0.9.3, 0.9.4 i 1.0-dev, ve všech se to projevuje stejně, pravděpodobně je to problém někde jinde než v jádru nette. Soubory jsem také projel skriptem na BOM, to jen pro info.

Layout mám standardní jednoduchý:

<?php
<body>
  @{block #content}
  @{/block}
</body>
?>

V šabloně pak:

<?php
@{block #content}

@{widget financesForm}

@{widget financesDataGrid}

@{/block}
?>

Pokud vyhodím ze šablony formulář, funguje datagrid ajaxově tak, jak má.. pokud tam přidám formulář, přestane fungovat a dostávám v odpovědi Invalid State Exception, že už byly odeslány hlavičky. Jak jsem našel v jiném vlákně, zkusil jsem do bootstrapu přidat ruční startování session, žel nepomohlo..

Neřešil jste pls někdo podobný problém?

Případně jak fungují správně nové šablony bez zavináčové magie, je někde nějaký popis?

Díky za spolupráci!

Michal

p.s. Omlouvám se za kód šablon v php blocích, nevím, jak na to líp, aby to nějak vypadalo..

Honza Kuchař
Člen | 1662
+
0
-

Formulář neumí AJAX (nepoužívá při vykreslování template). Zvináč pryč a bude to ok.

blacksun
Člen | 177
+
0
-

Óóó mocný, jak jednoduché.. Aneb jak vyřešit celodenní problém během deseti minut.. Holt sem to zavináčově přemagioval. Díky moc!

Jinak k té druhé části postu – existuje nějaký popis nebo topic na fóru, kde by se nějak popisovalo nové chování bez zavináčů? Fórum sleduju pravidelně, ale je možné, že mi něco uniklo.

despiq
Člen | 320
+
0
-

jenicek se ted nechava oslovovat Ooo mocny tak to je velmi zajimave
myslim ze se ajax bez zavinacu stale neobejde

mlha
Člen | 58
+
0
-

Jak mohu naučit formulář AJAX? Potřebuji zobrazit formulář pomocí AJAXu a pomocí AJAXu ho i odeslat.
Formulář ale není potomkem třídy Control, takže nemá metodu invalidateControl. Jaké by tedy mělo být standartní řešení.
Omlouvám se, pokud se jedná o triviální dotaz, s Nette začínam.

Díky

mlha
Člen | 58
+
0
-

Problém jsem vyřešil vlastní třídou komponenty odvozenou od \Nette\Application\Control.
Obsahuje form, na který jsou defaultně směrovány veškeré metody přes __call.

<?php
use Nette;

class FormDialog extends \Nette\Application\Control
{

  /** @var \Nette\Application\AppForm */
  private $form;

  /** @var \Nette\Web\Html Form title */
  private $title;

  /** @var bool */
  private $ajax=true;

  /** @var bool */
  private $forceShow=null;

  /** @var bool */
  private $closeButton=true;

  /** @var bool */
  /** @persistent bool */
  public $show;

  /** @var array of function(Form $sender); Occurs when the form is submitted and successfully validated */
  public $onSubmit;

  /** @var array of function(Form $sender); Occurs when the form is submitted and not validated */
  public $onInvalidSubmit;

  /** @var string class of div element */
  public $dialogClass = 'form_dialog';

  public function __construct($parent = NULL, $name = NULL)
  {
  	parent::__construct($parent, $name);
  	$this->form = new \Nette\Application\AppForm($this, 'formDialogForm');
  	$this-> $this->form->onSubmit;
  	$this-> $this->form->onInvalidSubmit;
  	$this->title = \Nette\Web\Html::el('h3');
  	//$form->form->onInvalidSubmit[] = callback($this, 'formValidationError');
  }

  /**
   * Return element prototype of nested Form
   * @return \Nette\Web\Html
   */
  public function getFormElementPrototype()
  {
  	return $this->form->getElementPrototype();
  }


  /**
   * Return title element protype
   * @return Html
   */
  public function getTitlePrototype()
  {
  	return $this->title;
  }


  /**
   * Set title
   * @param string $text
   */
  public function setTitleText($text)
  {
  	$this->title->setText($text);
  	$this->invalidateControl();
  }

  /**
   * Return nested Form
   * @return \Nette\Application\AppForm
   */
  public function getForm()
  {
  	return $this->form;
  }

  /**
   * Setter pro ajax
   * @return void
   */
  public function setAjax($bool)
  {
  	$this->ajax = $bool;
  }

  /**
   * Getter pro ajax
   * @return boolean
   */
  public function getAjax()
  {
  	return (boolean) $this->ajax;
  }

  /**
   * Setter pro CloseButton
   * @return void
   */
  public function setCloseButton($bool)
  {
  	$this->closeButton = $bool;
  }

  /**
   * Getter pro CloseButton
   * @return boolean
   */
  public function getCloseButton()
  {
  	return (boolean) $this->closeButton;
  }

  /**
   * Force Setter pro Show
   * @return void
   */
  public function forceShow($bool)
  {
  	$this->forceShow = $bool;
  }

  /*
   * Mapovani obecnych nedefinovanych method tridy na metody \Nette\Application\Control
   * @param String $procedureName
   * @param Array  $arguments
   * @return IDBProcedure
   */
  final public function __call($procedureName, $arguments=array())
  {
    try {
    $ref = new \ReflectionObject($this->form);
    $ret = null;
    if (!$ref->getMethod($procedureName)) throw new \Exception('Procedure `'.$procedureName.'` doesn`t exist!');

    $ret = call_user_func_array(array($this->form, $procedureName), $arguments);
    }
    catch (\Exception $e) {
      \Nette\Debug::log($e);
    }
    return $ret;
  }

  /**
   * Adds single-line color input control to the form.
   * @param  string  control name
   * @param  string  label
   * @return TextInput
   */
  public function addColorPicker($name, $label = NULL)
  {
    $input = $this->form->addText($name, $label, 6, 6);
    $input->getControlPrototype()->class('JSColorPicker');
    return $input;
  }

  /**
   * Adds single-line datetime input control to the form.
   * @param  string  control name
   * @param  string  label
   * @param  boolean with timepicker
   * @return TextInput
   */
  public function addDateTime($name, $label = NULL, $withTime=true)
  {
    //TODO: predelat na skutecny datetimepicker
    $input = $this->form->addText($name, $label, 25);
    return $input;
  }

  /**
   * Adds slider number input control to the form.
   * @param  string  control name
   * @param  string  label
   * @param  integer minimum
   * @param  integer maximum
   * @param  integer step
   * @return SelectBox
   */
  public function addSlider($name, $label = NULL, $min=0, $max=100, $step=1, $empty=FALSE)
  {
    $arr_hour = array();
    for ($i = $min; $i <= $max; $i=$i+$step) {
      $arr_hour[$i] = $i;
    }
    //TODO: predelat na skutecny slider
    $input = $this->form->addSelect($name, $label, $arr_hour, 1);
    if ($empty) $input->skipFirst('');
    return $input;
  }

  /**
   * Adds select box control that allows single item selection.
   * @param  string  control name
   * @param  string  label
   * @param  array   items from which to choose
   * @param  int     number of rows that should be visible
   * @return SelectBox
   */
  public function addSelect($name, $label = NULL, array $items = NULL, $size = NULL)
  {
  	return $this->form[$name] = new SelectBox($label, $items, $size);
  }


	/************** configuration **************/


	/************** signals processing **************/

	/**
	 * Handle close signal
	 */
	public function handleClose($id)
	{
	  if ($this->forceShow === null) $this->show = false;
	  else $this->show = $this->forceShow;
	  $this->invalidateControl();
	  if ($this->ajax && !$this->presenter->isAjax()) $this->presenter->redirect('this');
	}

	/**
	 * Handle show signal
	 */
	public function handleShow($id)
	{
	  if ($this->forceShow === null) $this->show = true;
	  else $this->show = $this->forceShow;
	  $this->invalidateControl();
	  if ($this->ajax && !$this->presenter->isAjax()) $this->presenter->redirect('this');
	}

	/************** rendering **************/

	/**
	 *
	 * @return bool
	 */
	public function isVisible()
	{
	  if (is_null($this->show)) $this->show = false;
	  return $this->show;
	}

	/**
	 * Template factory.
	 * @return ITemplate
	 */
	protected function createTemplate()
	{
		$template = parent::createTemplate();
		//$template->registerFilter('\Nette\Templates\LatteFilter::invoke');
		$template->setFile(dirname(__FILE__) . '/FormDialog.phtml');
		return $template;
	}


	public function render()
	{
	  if ($this->ajax) $this->getFormElementPrototype()->addClass('ajax');
	  $this->template->visible = $this->show;
	  $this->template->class = $this->dialogClass;
	  $this->template->title = $this->title;
	  $this->template->close = \Nette\Web\Html::el('div', array('class' => 'close'));
	  if ($this->closeButton) {
    	  $icon = \Nette\Web\Html::el('span');
    	  $icon->class('icon icon-close');
    	  $a = \Nette\Web\Html::el('a')->title('Zavřít');
    	  if ($this->ajax) $a->addClass('ajax');
    	  $a->add($icon);
    	  $a->href($this->link('close'));
    	  $this->template->close->add($a);
	  }
	  $this->template->jsscript = \Nette\Web\Html::el('script', array('type' => 'text/javascript', 'language' => 'javascript'));
	  $this->template->jsscript->setText('jscolor.init();');
	  return $this->template->render();
	}

}
?>

sablona (FormDialog.phtml)

<?php
{snippet}
{if $visible}
<div {if $class != '' }class="{$class}"{/if}>
	{$close}
	{$title}
	{widget formDialogForm}
	{$jsscript}
</div>
<div class="formdialog_curtain"></div>
{/if}
{/snippet}
?>

Součástí je i vlastní selectBox, který se umí chovat jako Submit tlačítko:

<?php
class SelectBox extends \Nette\Forms\SelectBox
{
  private $hasSubmit=false;

  /**
   * Adds to SelectBox ability to Submit form on change event
   * @param  string  control name
   * @param  string  caption
   * @return \Nette\Forms\SubmitButton
   */
  public function addSubmit($name, $caption = NULL)
  {
    if ($this->hasSubmit) throw new \InvalidArgumentException("Ability to Submit has been already added!");
    $form = $this->getForm();
    $submit = new \Nette\Forms\SubmitButton($caption);
    $form[$name] = $submit;
    $this->hasSubmit = true;
    $this->getControlPrototype()->onChange("this.form['".$name."'].click();");
    $submit->getControlPrototype()->style = array('display' => 'none');
    $submit->getLabelPrototype()->style = array('display' => 'none');
    return $submit;
  }
}
?>

Editoval mlha (10. 11. 2010 14:36)