Jak přidat class=“required“ k label v Nette/Latte při manuálním vykreslení formuláře

Od jisté verze už Latte nepřidává k prvku <label> class=“required“, pokud použijete manuální vykreslení formuláře.

To mi trochu vadí, protože po upgrade na nejnovější Nette 2.4 mi zmizí z formulářů hvězdičky označující povinná pole.

Hvězdičky jsem měl totiž nastavené pomocí CSS:

label.required:after {content:"*";}

Naštěstí existuje způsob, jak hvězdičky poměrně jednoduše vrátit. Spočívá to v tom, že si napíšeme vlastní Latte makro, kterým přetížíme výchozí chování makra {label}.

Vytvoříme si soubor MyFormMacros.php:

use Latte;
use Latte\MacroNode;
use Latte\PhpWriter;
use Latte\CompileException;
use Latte\Macros\MacroSet;


class MyFormMacros extends MacroSet
{

	public static function install(Latte\Compiler $compiler)
	{
		$me = new static($compiler);
		$me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd'], NULL, self::AUTO_EMPTY);
	}


	/**
	 * {label ...}
	 */
	public function macroLabel(MacroNode $node, PhpWriter $writer)
	{
		if ($node->modifiers) {
			throw new CompileException('Modifiers are not allowed in ' . $node->getNotation());
		}
		$words = $node->tokenizer->fetchWords();
		if (!$words) {
			throw new CompileException('Missing name in ' . $node->getNotation());
		}
		$node->replaced = true;
		$name = array_shift($words);
		return $writer->write(
			($name[0] === '$'
				? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word];'
				: '$_input = $_form[%0.word];') . '
			$attributes = %node.array;
			if ($_input->required) {
				if(array_key_exists("class", $attributes)) {
					$attributes["class"] .= " required";
				} else {
					$attributes += array("class" => "required");
				}
			}
			if ($_label = $_input->%1.raw) echo $_label->addAttributes($attributes)',
			$name,
			$words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()'
		);
	}


	/**
	 * {/label}
	 */
	public function macroLabelEnd(MacroNode $node, PhpWriter $writer)
	{
		if ($node->content != NULL) {
			$node->openingCode = rtrim($node->openingCode, '?> ') . '->startTag() ?>';
			return $writer->write('if ($_label) echo $_label->endTag()');
		}
	}
}

Jedná se o osekanou verzi Nette\Bridges\FormsLatte\FormMacros, kde jsem upravil chování ve funkci macroLabel.

Pak jen stačí přidat do config.neon následující řádky:

latte:
	macros:
		- MyFormMacros

A máme hotovo. Nyní bude mít každý required prvek vykreslený pomocí makra {label} třídu „required“.

Přiznám se, že úplně dopodrobna nerozumím, co se ve funkci macroLabel děje, takže je možné, že řešení není dokonalé a v některých use casech to může rozhodit dosavadní výchozí chování. V mém případě však fungovalo vše bez problémů.

5 thoughts on “Jak přidat class=“required“ k label v Nette/Latte při manuálním vykreslení formuláře”

  1. Ahoj Michale,

    funguje Ti tohle řešení i v Nette 2.4? Do verze 2.3 jsem to používal, ale už to nefunguje…

  2. Článek jsem psal podle fungující implementace na projektu s Nette 2.4 – výsledek je k vidění zde: http://www.firstclass.cz/casopis-fc/
    Takže funguje.
    Pokud Tobě ne, bude to nejspíš jen nějaká chybka, v principu to je ale řešitelný úkol.

  3. Díky, opravdu moje hloupá chyba… vyřešeno

  4. Ahoj Štěpáne,

    jaká byla Tvoje hloupá chyba?

    Snažím se implementovat řešení výše, ale také mi nefunguje. Díky.

  5. Ahoj. Děkuju moc za tento post, dost mi usnadnil život. Hrabat se ve střevech nette abych pochopil jak to funguje je opravdu těžké.
    Jen jsem narazil na problém, a tak sem přispěji. Toto tvé řešení nefunguje pro případ, kdy je ve formuláři container. Makro hodí chybu, že

    $_input->required

    není definováno pro container, což vskutku není. Procházel jsem API dokumentace nette, zda není user-friendly funkce na zjištění, jestli je objekt Container, a není. Takže jsem to vyřešil že před výše uvedenou řádku přidám

    if(!isset($_input->required)) return;

    Šlo by to asi i pomocí zjistění typu classy, ale bál bych se jestli to bude fungovat vždy. Poznámka: getHtmlAttribute() nelze použít, páč neexistuje v Container…

    Note: mám php verzi 7.029-1, web apache2, nette verze 2.3

Komentáře nejsou povoleny.