Redraw control – end() expects parameter 1 to be array, null given
- cafesk8
- Člen | 103
Zdravím,
mám v multi-step formuláři (webchemistry/wizard) na druhém kroku text input, dle jehož hodnoty potřebuji nastavit hodnoty v selectboxu. V js volám na onChange hadnle v presenteru, který mi má hodnoty selectboxu nastavit, při redrawControl však dojde k chybě end() expects parameter 1 to be array, null given
mám presenter:
final class MultiPresenter extends BasePresenter {
/** @var Wizard */
private $wizard;
public function __construct(Wizard $wizard) {
$this->wizard = $wizard;
}
public function handleChangeStep($step): void {
$this->getComponent("wizard")->setStep($step);
}
protected function createComponentWizard(): Wizard {
return $this->wizard;
}
public function handleZip($cislo) {
$hodnoty_do_selectu = $vypocet_z_cislo;
$formular = $this->getComponent('wizard')->getComponent('step2');
$formular['object_city']->setItems($hodnoty_do_selectu);
if ($this->isAjax()) {
$this->redrawControl('psc_wrapper');
$this->redrawControl('psc');
} else {
$this->redirect('this');
}
}
}
šablonu:
{block content}
<div n:wizard="wizard" class="form-navigation">
<ul n:if="!$wizard->isSuccess()" class="nav nav-pills nav-justified">
<li n:foreach="$wizard->steps as $step" class="nav-item">
...
</li>
</ul>
{step 1}
{form $form}
....
{/form}
{/step}
{step 2}
{form $form}
{snippetArea psc_wrapper}
{input object_type}
{input object_zip}
{snippet psc}
{input object_city}
{/snippet}
{input ins_value}
{input phone}
{input prev}
{input next}
{/snippetArea}
{/form}
{/step}
{step 3}
{form $form}
....
{/form}
{/step}
{step success}
....
{/step}
</div>
{/block}
{block scripts}
<script n:syntax="double">
var psc_link = {{link zip!}};
</script>
{include parent}
{/block}
a js:
$('.zip_field').each(function(){
var $parent = $(this).closest('form');
$(this).change(function (e) {
var psc = $(this).val();
$.nette.ajax({
type: 'POST',
url : $zip_url,
data: {cislo: psc}
});
return false;
});
});
Pokud dám snippet někam mimo formulář a zkouším do něj přes ajax posílat nějaké hodnoty nebo klidně i výsledek selectu, tak je to OK, pokud se však snažím překreslit část ve {form}{/form} – dojde k chybě. Jak jde vidět, tak jsem zkusil i obalit do {snippetArea} a invalidovat i ji, bohužel nepomohlo.
Zkoušel jsem obalit i celý form, ale to skončí chybou: Undefined variable: form
{snippetArea psc_wrapper}
{form $form}
....
{snippet psc}
{input object_city}
{/snippet}
...
{/form}
{/snippetArea}
Když do snippetArea obalím celý {step}{/step}, tak mi vyskočí chyba: Undefined variable: wizard
Nesetkal jste se s tím někdo?
- cafesk8
- Člen | 103
@Martk : nic Vás nenapadá, nemáte nějaký funkční příklad překreslení snippetu v nějakém kroku?
děkuji
cafesk8 napsal(a):
To jsem také zkoušel, ale to mi skončí další chybou a to: Creating default object from empty value.
Source file: /vendor/latte/latte/src/Latte/Engine.php(161) : eval()'d code:122Martk napsal(a):
Měl bys celé n:wizard obalit, tam se vytváří proměnná $wizard
- cafesk8
- Člen | 103
Zkusil jsem to, ale bylo mi řečeno že Wizard->getFacade() neexistuje. Udělal jsem nejjednodušší příklad z nette/sandbox:
HomepagePresenter.php
namespace App\Presenters;
use Wizard;
final class HomepagePresenter extends BasePresenter {
public function renderDefault() {
$this->template->anyVariable = 'any value';
}
/** @var Wizard */
private $wizard;
public function __construct(Wizard $wizard) {
$this->wizard = $wizard;
}
public function handleChangeStep($step): void {
$this->getComponent("wizard")->setStep($step);
}
protected function createComponentWizard(): Wizard {
return $this->wizard;
}
public function handlePopulate($cislo) {
$form = $this->getComponent('wizard')->getComponent('step2');
$form['need_to_populate']->setItems(array('one' => 'ONE', 'two' => 'TWO'));
if ($this->isAjax()) {
$this->redrawControl('myArea');
$this->redrawControl('mySnippet');
} else {
$this->redirect('this');
}
}
}
Wizard.php
use Nette\Application\UI\Form;
class Wizard extends WebChemistry\Forms\Controls\Wizard {
protected function finish(): void {
$values = $this->getValues();
}
protected function createStep1(): Form {
$form = $this->createForm();
$form->addText('name', 'User name')
->setRequired();
$form->addSubmit(self::NEXT_SUBMIT_NAME, 'Next');
return $form;
}
protected function createStep2(): Form {
$form = $this->createForm();
$form->getElementPrototype()->class = 'ajax';
$form->addText('populate_on_change', 'Email')
->setRequired();
$form->addSelect('need_to_populate','Naplnit',array());
$form->addSubmit(self::PREV_SUBMIT_NAME, 'Back');
$form->addSubmit(self::NEXT_SUBMIT_NAME, 'Next');
return $form;
}
protected function createStep3(): Form {
$form = $this->createForm();
$form->addText('email', 'Email')
->setRequired();
$form->addSubmit(self::PREV_SUBMIT_NAME, 'Back');
$form->addSubmit(self::FINISH_SUBMIT_NAME, 'Register');
return $form;
}
}
Homepage/default.php
{block content}
{snippetArea myArea}
<div n:wizard="wizard">
<ul n:if="!$wizard->isSuccess()">
<li n:foreach="$wizard->steps as $step" n:class="$wizard->isDisabled($step) ? disabled, $wizard->isActive($step) ? active">
<a n:tag-if="$wizard->useLink($step)" n:href="changeStep! $step">{$step}</a>
</li>
</ul>
{step 1}
{control $form}
{/step}
{step 2}
{form $form}
{input populate_on_change, class=>"watch_this"}
{snippet mySnippet}
{input need_to_populate}
{/snippet}
{input next}
{input prev}
{/form}
{/step}
{step 3}
{control $form}
{/step}
{step success}
Registration was successful
{/step}
</div>
{/snippetArea}
{/block}
{block scripts}
<script n:syntax="double">
var handle_link = {{link populate!}};
</script>
{include parent}
{/block}
main.js
$(function(){
var $hadnle_url = handle_link;
$('.watch_this').each(function(){
$(this).change(function (e) {
var cislo = $(this).val();
$.nette.ajax({
type: 'POST',
url : $hadnle_url,
data: {cislo: cislo}
});
return false;
});
});
});
Nyní, když si stránku v prohlížeči načtu, tak mám hlášku:
„Warning: Creating default object from empty value“
„Source file: vendor/latte/latte/src/Latte/Engine.php(161) : eval()'d
code:58“
Call stack:
- …/vendor/latte/latte/src/Latte/Runtime/Template.php:282 source Template98aabccf63->blockMyArea(arguments)
- inner-code:49 Latte\Runtime\Template->renderBlock(arguments)
- …/vendor/latte/latte/src/Latte/Runtime/Template.php:282 source Template98aabccf63->blockContent(arguments)
…
V arguments bodu 2 je:
$name „_myArea“
$params array(..)
Pokud dám z šablony pryč snippetArea tak se formulář vykreslí ale při změně inputu vyskočí hláška: Redraw control – end() expects parameter 1 to be array, null given
Soubor s daty kdyžtak zde
Martk napsal(a):
@cafesk8 Zkus dát proměnnou do šablony přes action metodu:
$this->template->wizard = new WebChemistry\Forms\Controls\Wizard\Facade($this['wizard']->getFacade());
nejlepší by bylo zjištění jaký kus kódu dělá problém.
Editoval cafesk8 (8. 1. 2019 11:00)
- Martk
- Člen | 661
Tvoje ukázka mi v sandboxu fungovala:
"php": ">=7.2.0",
"nette/application": "^2.4.4",
"nette/bootstrap": "^2.4.3",
"nette/caching": "^2.5",
"nette/database": "^2.4",
"nette/di": "^2.4",
"nette/finder": "^2.4",
"nette/forms": "^2.4",
"nette/http": "^2.4",
"nette/mail": "^2.4",
"nette/robot-loader": "^2.4 || ^3.0",
"nette/safe-stream": "^2.3",
"nette/security": "^2.4",
"nette/utils": "^2.4",
"latte/latte": "^2.4",
"tracy/tracy": "^2.4",
"dg/adminer-custom": "^1.9",
"webchemistry/forms-wizard": "dev-master"
PHP 7.3.0, latte: v2.4.8
- cafesk8
- Člen | 103
@Martk : Bohužel, mně ne, ale jedu na PHP 7.1, zkusím upgrade na 7.3 a uvidím, ale ty verze mám stejný jako ty :/ Dám vědět.
Martk napsal(a):
Tvoje ukázka mi v sandboxu fungovala:
"php": ">=7.2.0", "nette/application": "^2.4.4", "nette/bootstrap": "^2.4.3", "nette/caching": "^2.5", "nette/database": "^2.4", "nette/di": "^2.4", "nette/finder": "^2.4", "nette/forms": "^2.4", "nette/http": "^2.4", "nette/mail": "^2.4", "nette/robot-loader": "^2.4 || ^3.0", "nette/safe-stream": "^2.3", "nette/security": "^2.4", "nette/utils": "^2.4", "latte/latte": "^2.4", "tracy/tracy": "^2.4", "dg/adminer-custom": "^1.9", "webchemistry/forms-wizard": "dev-master"
PHP 7.3.0, latte: v2.4.8
- cafesk8
- Člen | 103
@Martk
Žádný úspěch ani na PHP 7.3
composer.json
{
"name": "nette/sandbox",
"description": "The sandbox is a pre-packaged Nette Framework project, basic configured structure for your application.",
"homepage": "https://nette.org",
"type": "project",
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/en/contributors?lang=en"
}
],
"require": {
"php": ">=7.2.0",
"nette/application": "^2.4.4",
"nette/bootstrap": "^2.4.3",
"nette/caching": "^2.5",
"nette/database": "^2.4",
"nette/di": "^2.4",
"nette/finder": "^2.4",
"nette/forms": "^2.4",
"nette/http": "^2.4",
"nette/mail": "^2.4",
"nette/robot-loader": "^2.4 || ^3.0",
"nette/safe-stream": "^2.3",
"nette/security": "^2.4",
"nette/utils": "^2.4",
"latte/latte": "^2.4",
"tracy/tracy": "^2.4",
"dg/adminer-custom": "^1.9",
"webchemistry/forms-wizard": "dev-master"
},
"require-dev": {
"nette/tester": "^2.0"
},
"minimum-stability": "stable",
"config": {
"platform": {
"php": "7.3"
}
}
}
Když dám pryč snippetArea tak se web normálně rozběhne, ale při změně inputu mi vyskočí hláška „end() expects parameter 1 to be array, null given“. Když tam snippetArea nechám, tak mni stránka ani nenajede a mám tam pořád chybu „Creating default object from empty value“. Nenapadá Vás ještě něco? Případně je nějaká možnost se spojit?
cafesk8 napsal(a):
@Martk : Bohužel, mně ne, ale jedu na PHP 7.1, zkusím upgrade na 7.3 a uvidím, ale ty verze mám stejný jako ty :/ Dám vědět.
Martk napsal(a):
Tvoje ukázka mi v sandboxu fungovala:
"php": ">=7.2.0", "nette/application": "^2.4.4", "nette/bootstrap": "^2.4.3", "nette/caching": "^2.5", "nette/database": "^2.4", "nette/di": "^2.4", "nette/finder": "^2.4", "nette/forms": "^2.4", "nette/http": "^2.4", "nette/mail": "^2.4", "nette/robot-loader": "^2.4 || ^3.0", "nette/safe-stream": "^2.3", "nette/security": "^2.4", "nette/utils": "^2.4", "latte/latte": "^2.4", "tracy/tracy": "^2.4", "dg/adminer-custom": "^1.9", "webchemistry/forms-wizard": "dev-master"
PHP 7.3.0, latte: v2.4.8
- Martk
- Člen | 661
Poslal jsem jeden commit na git, možná to bylo tím. Jestli ne, tak jsem na https://pehapkari.slack.com pod stejným nickem jako tady.
PS: je potřeba vymazat latte cache
Editoval Martk (9. 1. 2019 15:37)
- cafesk8
- Člen | 103
@Martk: Super! Pomohlo to, díky moc!
Martk napsal(a):
Poslal jsem jeden commit na git, možná to bylo tím. Jestli ne, tak jsem na https://pehapkari.slack.com pod stejným nickem jako tady.
PS: je potřeba vymazat latte cache
- cafesk8
- Člen | 103
@Martk: Hodnoty se mi do selectu naplní v pořádku, problém nastane ve chvíli, kdy pokračuji na další krok. Hodnota se neuloží, tudíž s ní nemůžu dále pracovat. Při getValues() je výsledek tohoto pole vždy null.
Potřeboval bych totiž v dalším kroku dle hodnoty, kterou někdo v předchozím selectu vybral naplnit další select.
Editoval cafesk8 (10. 1. 2019 16:47)
- Martk
- Člen | 661
@cafesk8 Je to tím, že nette porovnává odeslanou hodnotu s tím, co je v $items v selectboxu. V této době je $items === [] . Kdyby to nedělal, tak by uživatel mohl podstrčit jakoukoliv vlastní hodnotu.
Zkus udělat tohle ve formuláři:
$form->onAnchor[] = function (Form $form): void {
if (!$form->isSubmitted()) {
return;
}
$populateOnChange = $form->getValues(true)['populate_on_change'];
$form['need_to_populate']->setItems([
'one' => 'ONE',
'two' => 'TWO',
]);
};
- cafesk8
- Člen | 103
@Martk Super, tohle funguje.
Dle hodnoty v radio listu v kroku č. 1 naplním v kroku č. 2 select,
mohu přecházet tam a zpátky a vše funguje OK.
Co se mi však nedaří je, že když se vrátím zpět na krok č. 1 a zvolím
v radio listu jinou možnost než zvolenou původně, tak se mi již nepodaří
dostat na krok č. 2, kvůli právě ochranně vkládání polí.
Value ‚one_a‘ is out of allowed set [‚one_b‘, ‚two_b‘] in field ‚need_to_populate‘.
Tudíž bych po změně v kroku č. 1 potřeboval jakoby vyresetovat hodnotu z kroku č. 2, něco jako
function createStep2() {
if($step1['radiolist'] !== $formvalues['radiolist']) {
// vyresetovat hodnotu z prvního kroku abych mohl naplnit select v kroku č. 2
}
}
Ráno zkusím kdyžtak sepsat příklad jak to mám teď.
Martk napsal(a):
@cafesk8 Je to tím, že nette porovnává odeslanou hodnotu s tím, co je v $items v selectboxu. V této době je $items === [] . Kdyby to nedělal, tak by uživatel mohl podstrčit jakoukoliv vlastní hodnotu.
Zkus udělat tohle ve formuláři:
$form->onAnchor[] = function (Form $form): void { if (!$form->isSubmitted()) { return; } $populateOnChange = $form->getValues(true)['populate_on_change']; $form['need_to_populate']->setItems([ 'one' => 'ONE', 'two' => 'TWO', ]); };
Editoval cafesk8 (15. 1. 2019 17:05)
- cafesk8
- Člen | 103
Dočasně jsem vyřešil přes:
->checkAllowedValues = false
cafesk8 napsal(a):
@Martk Super, tohle funguje.
Dle hodnoty v radio listu v kroku č. 1 naplním v kroku č. 2 select, mohu přecházet tam a zpátky a vše funguje OK.
Co se mi však nedaří je, že když se vrátím zpět na krok č. 1 a zvolím v radio listu jinou možnost než zvolenou původně, tak se mi již nepodaří dostat na krok č. 2, kvůli právě ochranně vkládání polí.Value ‚one_a‘ is out of allowed set [‚one_b‘, ‚two_b‘] in field ‚need_to_populate‘.
Tudíž bych po změně v kroku č. 1 potřeboval jakoby vyresetovat hodnotu z kroku č. 2, něco jako
function createStep2() { if($step1['radiolist'] !== $formvalues['radiolist']) { // vyresetovat hodnotu z prvního kroku abych mohl naplnit select v kroku č. 2 } }
Ráno zkusím kdyžtak sepsat příklad jak to mám teď.
Martk napsal(a):
@cafesk8 Je to tím, že nette porovnává odeslanou hodnotu s tím, co je v $items v selectboxu. V této době je $items === [] . Kdyby to nedělal, tak by uživatel mohl podstrčit jakoukoliv vlastní hodnotu.
Zkus udělat tohle ve formuláři:
$form->onAnchor[] = function (Form $form): void { if (!$form->isSubmitted()) { return; } $populateOnChange = $form->getValues(true)['populate_on_change']; $form['need_to_populate']->setItems([ 'one' => 'ONE', 'two' => 'TWO', ]); };