Dynamický závislý select ve formulářích
Jde např. o případ, kdy uživatel vybere nějaký kraj a následně se mu načtou města příslušné danému kraji pěkně z databáze. Vyžaduje jQuery 1.4.3+ a Ajax s jQuery.
Přidávací formulář
Šablona
{snippet form}
{control selectForm}
{/snippet}
<script type="text/javascript">
$("form").delegate('#'+{$control["selectForm-static"]->htmlId}, 'change', function() {
$.get("?do=selectLoad", {"static": $(this).val()});
});
</script>
Budete-li mít problémy při opakovaném zvolení hodnoty ze selectu, můžete zkusit zahrnout navěšený js do snippetu.
Presenter
class myPresenter extends BasePresenter
{
/**
* Loads new values to select
* @param int value from parent select
* @return array values for dynamic select
**/
public function handleSelectLoad($static_id)
{
$form = $this->getComponent("selectForm"); // our form
// for demo only! this part will use database to load your select using $value
// $this->models->options->getItemsForGroup($static_id);
$newArray = array(
"I am new, I have changed!",
);
$form["dynamic"]->setItems($newArray); // set up new values
$this->invalidateControl("form"); // invalidate ajax snippet
}
/**
* Simple form
**/
protected function createComponentSelectForm()
{
$staticArray = array(
"I am static",
"I am static two/too",
);
$dynamicArray = array(
"Change the 'static' and I will change",
"Me too",
);
$form = new Form;
$form->addSelect("static","Choose me:", $staticArray);
$form->addSelect("dynamic","I am dynamic:", $dynamicArray);
$form->addSubmit("send", "Submit");
$form->onSuccess[] = callback($this, "selectFormSent");
return $form;
}
/**
* Shows values from selects
* @param form
**/
public function selectFormSent(Form $form)
{
$values = $form->getHttpData(); // getValues() is not enough for $form["dynamic"]
unset($values["send"]); // we don't need this
// save values...
}
}
Editovací formulář
Pokud formulář využíváme k editování, musíme steženějní funkci předat 2 id – id upravovaného záznamu a id statického select boxu. Jinak je princip stejný.
class myPresenter extends BasePresenter
{
/**
* Loads new values to select
* @param int record id (url: mysite.com/record/edit/5)
* @param int value from parent select
* @return array values for dynamic select
**/
public function handleSelectLoad($record_id, $static_id)
{
$form = $this->getComponent("selectForm"); // our form
// for demo only! this part will use database to load your select using $value
// $this->models->options->getItemsForGroup($value);
$newArray = array(
"I am new, I have changed!",
);
// we edit the record -> load it's values
if($this->presenter->view == "edit" AND isset($record_id)) {
$defaults = $this->models->record->item($record_id);
$form->setDefaults($defaults);
}
// in case we need save dynamic_id as parent_id = make possible to choose only the parent_id
$newArray[$static_id] = "Right under the static_id";
$newArray = $newArray + $this->models->cell->getChildren($main_id);
$form["static"]->setValue($static_id);
$form["dynamic"]->setItems($newArray); // set up new values
$this->invalidateControl("form"); // invalidate ajax snippet
}
// Form + it's submit function are the same
// ...
}
Více závislých selectů
Pokud původní zadání s městy rozšíříme ještě o městské části.
- rozšíříme původní js pro select o načtení městských částí první načtené položky do selectu s městy
- přidáme js pro select městkých částí
- přidáme funkci pro načítání městských částí
Šablona
{snippet form}
{control selectForm}
{/snippet}
<script type="text/javascript">
// main_id select changed
$("form").delegate('#frmactForm-main_id', 'change', function(e){
$.get("?do=selectLoad&main_id="+$(this).val());
var main_id = $("#frmactForm-main_id").val();
var select_id = $("#frmactForm-parent_id").val();
$.get("?do=selectLoad2&parent_id="+select_id+"&main_id="+main_id);
});
// parent_id select changed
$("form").delegate('#frmactForm-parent_id', 'change', function(e){
var main_id = $("#frmactForm-main_id").val();
$.get("?do=selectLoad2&parent_id="+$(this).val()+"&main_id="+main_id);
});
</script>
Presenter
/**
* Loads values to select by value
* @mixed value from select1
**/
public function handleSelectLoad2($record_id, $parent_id, $main_id)
{
$form = $this->getComponent("selectForm");
// values for the record
if($this->presenter->view == "edit" AND isset($record_id)) {
$defaults = $this->models->myModel->item($record_id);
$form->setDefaults($defaults);
}
$selectValues1 = $this->models->myModel->getChildren($main_id);
$selectValues = $this->models->myModel->getChildren($parent_id);
if(!count($selectValues)) {
$selectValues[NULL] = "No item";
}
// selected main value
$form["main_id"]->setValue($main_id);
$selectParentValues = $this->models->myModel->getChildren($main_id);
$form["parent_id"]->setItems($selectParentValues);
$form["parent_id"]->setValue($parent_id);
$form["real_parent_id"]->setItems($selectValues);
$this->invalidateControl("form");
}
/**
* Simple form
**/
protected function createComponentSelectForm()
{
//...
// extend the form by another select and that's it
$form->addSelect("real_parent_id", ...);
//...
}
thorn | 15. 3. 2012, 18:45 | question
Ahoj, dotaz, da se to ajaxove volani nejak prizpusobit, pokud uz do presenteru potrebuju vstoupit nejakou hodnotou? Napriklad kdyz mam: {presenter: $id}, vytvori mi to odkaz ../presenter/?id=2, v ajaxu vytvaris pozadavek $.GET(„?do=selectLoad“..);, jenze ten otaznik tomu tedkom vadi, kdyz ho zamenim za &, aby to bylo jako neco ../presenter/?id=2&form tak to taky nejde, jak na to?