Vypsání inputu v komponentě

martinzi
Člen | 6
+
0
-

Zdravím všechny,

Jsem naprostý začátečník v Nette a začal jsem dělat jednoduchý redakční systém webů.

Mám tedy formulář, který manuálně vykresluji v šabloně, do které includnu šablonu s inputy, které zrovna potřebuji (na základě stránce, kterou edituji). Vzhledem k množství opakujících se stejných inputů jsem se rozhodl vytvořit komponentu (zatím neznám jiný způsob.)

Šablona s inputy:

<div class="form-check">
    <input n:name="single_product_btn_value" class="form-check-input" id="single_product_btn_value">
    <label class="form-check-label" for="single_product_btn_value">
        Kategorie
    </label>
</div>

<div class="form-check">
    <input n:name="single_product_heading" class="form-check-input" id="single_product_heading">
    <label class="form-check-label" for="single_product_heading">
        Header
    </label>
</div>

Namísto repetetivního přepisování chci docílit něčeho takového

{var $inputText = "Product"}
{var $inputName = "single_product_btn_value"}
{control checkbox $inputText, $inputName}

vytvořil jsem si tedy componentu v AppearancePresenter

...
protected function createComponentCheckbox()
{
	$control = new \CheckboxControl;
	return $control;
}
...

Ve složce components mám CheckboxControl.php

use Nette\Application\UI\Control;

class CheckboxControl extends Control
{
    // public function render(string $inputName, string $inputText)
    public function render(string $inputText, string $inputName)
    {
        $template = $this->template;

        // nastavení šablony
        $template->setFile(__DIR__ . '/checkbox.latte');

        // nastavení proměnné z parametru
        $template->inputText = $inputText;
        $template->inputName = $inputName;

        $template->render();
    }
}

a checkbox.latte

<div class="form-check">
    <input n:name="{$inputName}" class="form-check-input" id="{$inputName}">
    <label class="form-check-label" for="{$inputName}">
        {$inputText}
    </label>
</div>

Problém je v n:name, protože když tam není, vše funguje.
Vyhazovaná chyba – end() expects parameter 1 to be array, null given

Předem děkuji za tipy a rady.

netteman
Člen | 126
+
0
-

Takže metoda (nejspíš v presenteru)

createComponentNazevFormulare(){}

je pořád stejná a v templatu se mění jenom zobrazované inputy?

Editoval netteman (15. 1. 2022 16:17)

Milo
Nette Core | 1283
+
+1
-

Input, aby měl HTML jméno a mohl se vykreslit, musí být připojen k formuláři. A to nevidím, že někde děláš.

martinzi
Člen | 6
+
0
-

@netteman – mám pouze jeden formulář a v něm veliké množství inputů různého druhu. Přemýšlel jsem že, jak vypisování zjednodušit a napadlo mě udělat na každý typ inputu jednu komponentu, kterou vypíšu. (jedna komponenta obsahuje pouze jeden input)

{block checkbox}

{* <div class="form-check">
    <input n:name="{$inputName}" class="form-check-input" id="{$inputName}">
    <label class="form-check-label" for="{$inputName}">
        {$inputText}
    </label>
</div>

{/block}

@Milo – Presenter jsem sem nechtěl dávat, je to celé jeden vyliký zmatek ale mám to všechno tam. (Bez komponenty vše funguje).
Celý problém spočívá v tom, že když napíšu input ručně vše funguje, ale když přes komponentu, input nefunguje a vyhazuje chybu.

Presenter AppearancePresenter.php:

<?php

declare(strict_types=1);

namespace AdminModule;

use Nette;
use Nette\Application\UI\Form;
use Nette\Utils\DateTime;

final class AppearancePresenter extends Nette\Application\UI\Presenter
{
	protected function startup()
	{
		parent::startup();
		if (!$this->getUser()->isLoggedIn()) {
			$this->redirect('Homepage:default');
		}
	}

	private Nette\Database\Explorer $database;

	public function __construct(Nette\Database\Explorer $database)
	{
		$this->database = $database;
	}

	protected function createComponentCheckbox()
	{
		$control = new \CheckboxControl;
		return $control;
	}

	public function renderGlobal(string $editedPage = null): void {
		........
	}

	protected function createComponentNewForm(): Form
    {
		$web_structure = $this->database
			->table("web_structure");

		$web_colors = $this->database
			->table("web_colors");

		$web_content = $this->database
			->table("web_content");

		$web_info = $this->database
			->table("web_info")
			->get(1);

		$gdpr = $this->database
			->table("officials")
			->where("type", "gdpr")
			->fetch();

		$termsandconditions = $this->database
			->table("officials")
			->where("type", "termsandconditions")
			->fetch();

		$form = new Form;

		$form->addText("basicWebInfo_name")
			->setDefaultValue($web_info->name);

		$form->addUpload("faviconImg", "Favicon");

		$input_list_display = [];

		$httpRequest = $this->getHttpRequest();
        $url = $httpRequest->getUrl();
		$url = strval($url);
		$sanitizeGet = explode("=", strtolower($url));
		if (count($sanitizeGet) >= 2) {
			$sanitizeGet2 = explode("%3a", $sanitizeGet[1]);
		}else{
			$sanitizeGet2[0] = "homepage";
			$sanitizeGet2[1] = "default";
		}
		$actualPageLink = $sanitizeGet2[0] . ":" . $sanitizeGet2[1];

		foreach($web_structure as $structure_section){
			if(strtolower($structure_section->for_page) == $actualPageLink){
				if($structure_section->type == "checkbox"){
					${$structure_section->sec_name} = $structure_section->display;

					array_push($input_list_display, $structure_section->sec_name);

					$form->addCheckbox($structure_section->sec_name)
					->setValue($structure_section->display);
				}
			}
		}
		if(count($input_list_display) == 0){
			$input_list_display = "none";
		}

		$input_list_colors = [];
		foreach($web_colors as $color){
			if($color->editable == 1){
				if(strtolower($color->for_page) == $actualPageLink){
					array_push($input_list_colors, $color->name);

					$form->addText($color->name)
						->setHtmlType("color")
						->setDefaultValue($color->value);
				}
			}
		}
		if(count($input_list_colors) == 0){
			$input_list_colors = "none";
		}

		$input_list_text = [];
		foreach($web_content as $content){
			if(strtolower($content->for_page) == $actualPageLink){
				array_push($input_list_text, $content->name);

				$form->addText($content->name)
					->setDefaultValue($content->content);
			}
		}
		if(count($input_list_text) == 0){
			$input_list_text = "none";
		}

		if($actualPageLink == "officials:gdpr"){
			$form->addTextArea($gdpr->type)
				->setAttribute("rows", 10)
				->setDefaultValue($gdpr->content);
		}

		if($actualPageLink == "officials:termsandconditions"){
			$form->addTextArea($termsandconditions->type)
				->setAttribute("rows", 10)
				->setDefaultValue($termsandconditions->content);
		}

		if($input_list_display != "none"){
			$input_list_display = implode(", ", $input_list_display);
		}
		$form->addText("input_list_display")
			->setDefaultValue($input_list_display);

		if($input_list_colors != "none"){
			$input_list_colors = implode(", ", $input_list_colors);
		}
		$form->addText("input_list_colors")
			->setDefaultValue($input_list_colors);

		if($input_list_text != "none"){
			$input_list_text = implode(", ", $input_list_text);
		}
		$form->addText("input_list_text")
			->setDefaultValue($input_list_text);

        $form->addSubmit('send', 'Uložit a aktualizovat');
        $form->onSuccess[] = [$this, 'newFormSubmited'];

        return $form;
    }

    public function newFormSubmited(\stdClass $values): void
    {
		// foreach input on page update his value in database
		if($values->input_list_display != "none"){
			$input_list_display = explode(", ", $values->input_list_display);

			foreach($input_list_display as $input){
				$this->database
				->table('web_structure')
				->where('sec_name', $input)
				->update([
					'display' => $values->{$input},
				]);
			}
		}

		// foreach color in database save new value
		if($values->input_list_colors != "none"){
			$input_list_colors = explode(", ", $values->input_list_colors);

			foreach($input_list_colors as $color){
				$this->database
					->table('web_colors')
					->where('name', $color)
					->update([
						'value' => $values->{$color},
					]);
			}
		}

		// // update content in footer
		if($values->input_list_text != "none"){
			$input_list_text = explode(", ", $values->input_list_text);

			foreach($input_list_text as $text){
				$this->database
					->table("web_content")
					->where("name", $text)
					->update([
						"content" => $values->{$text},
					]);
			}
		}

		// update web_info name of website
		if($values->basicWebInfo_name){
			$this->database
				->table("web_info")
				->get(1)
				->update([
					"name" => $values->basicWebInfo_name,
				]);
		}

		if(isset($values->gdpr)){
			if($values->gdpr != ""){
				$this->database
					->table("officials")
					->where("type", "gdpr")
					->update([
						"content" => $values->gdpr,
					]);
			}
		}

		// favicon update
		$file = $values->faviconImg;
		if($file->isImage() and $file->isOk()) {
			$webInfo = $this->database
				->table("web_info")
				->get(1);

			$old_favicon = $webInfo->favicon_name;

			$old_path = "/hosting/www/martinzach.cz/bootstrapuser/www/images/" . $old_favicon;
			if(file_exists($old_path)){
				unlink($old_path);
			}

			$file_ext = strtolower(mb_substr($file->getSanitizedName(), strrpos($file->getSanitizedName(), ".")));

			$new_file_name = "favicon" . $file_ext;
			$file->move("/hosting/www/martinzach.cz/bootstrapuser/www/images/" . $new_file_name);

			$this->database
				->table("web_info")
				->get(1)
				->update([
					"favicon_name" => $new_file_name
			]);
		}

        $this->redirect('this');
    }
}
Milo
Nette Core | 1283
+
+2
-

Zapouzdřit jeden input formuláře do samostatné komponenty moc jednoduše nejde. Do komponent se zapouzdřují většinou celé formuláře. Zkus to jinak.

V úvodu ukazuješ svoji šablonu. Zkus to takhle:

<div class="form-check">
    <input n:name="single_product_btn_value" class="form-check-input">
	<label n:name="single_product_btn_value" />
</div>

<div class="form-check">
    <input n:name="single_product_heading" class="form-check-input">
	<label n:name="single_product_heading" />
</div>

Už to zápis zkrátí. Nebo se podívej do dokumentace na makra {input ...} a {label ...}.

V latte si pro opakující se části můžeš definovat bloky. Například (píšu to z hlavy):

{define form-input}
<div class="form-check">
    <input n:name="$name" class="form-check-input">
	<label n:name="$name" />
</div>
{/define}

{include form-input, name: single_product_btn_value}
{include form-input, name: single_product_heading}
martinzi
Člen | 6
+
0
-

Díky, moc pomohlo, bloky mně napadly hned jako první, ale netušil jsem, že k nim mohu přidat i hodnoty a použít je jako „funkci“.