Estrutura de formulário
@madWire
mad:model
@madBind
mad-text
mad-show
Two-way binding (mad:model.live + @madBind)
Input nativo sincroniza com a prop PHP a cada tecla (debounce), e @madBind reflete o valor sem re-renderizar a página.
Olá, ! O texto acima atualiza a cada tecla
(debounce de 300ms), sem re-renderizar a página inteira — @madBind é o patch mais leve do MadWire.
resources/views/tutor/examples/estrutura-reatividade/two-way.blade.php
@php
// $that (como $__component) e uma variavel LEXICAL setada por
// MadComponent::render() no template de TOPO da pagina. Este partial e
// incluido de dentro do componente Blade nativo tutor-demo (escopo
// isolado), entao $that nao chega ate aqui sozinho — precisa ser
// reobtido via o stack estatico de MadRenderContext (push/pop em
// MadComponent::render(), atravessa qualquer aninhamento de componentes).
$that = \Mad\Component\MadRenderContext::getComponent();
@endphp
<div style="max-width:420px;">
<label class="mad-label">Seu nome</label>
<input class="mad-input" type="text" mad:model.live="nomeReativo" value="{{ $that->nomeReativo }}"
placeholder="Digite seu nome...">
<p style="margin-top:.75rem;">
Olá, <strong>@madBind('nomeReativo')</strong>! O texto acima atualiza a cada tecla
(debounce de 300ms), sem re-renderizar a página inteira — <code>@madBind</code> é o patch mais leve do MadWire.
</p>
</div>
Estado reativo com @madWire + mad-text
@madWire expõe props publicas como estado Alpine; mad-text reage a cada mudança vinda do servidor (mad:click).
resources/views/tutor/examples/estrutura-reatividade/contador.blade.php
<div @madWire(['contador'])>
<div mad-text="contador" style="font-size:2.5rem;font-weight:700;color:var(--mad-primary);"></div>
<div style="display:flex;gap:.5rem;margin-top:.75rem;">
<mad-btn variant="outline" icon="minus" mad:click="onDecrementarContador">-1</mad-btn>
<mad-btn variant="primary" icon="plus" mad:click="onIncrementarContador">+1</mad-btn>
<mad-btn variant="ghost" icon="rotate-ccw" mad:click="onResetarContador">Zerar</mad-btn>
</div>
</div>
app/control/Tutor/TutorEstruturaReatividade.php
/** Two-way binding puro: mad:model.live sincroniza sem chamar nenhuma action. */
public function onIncrementarContador(): void
{
$this->contador++;
}
mad-show alternando conteúdo por estado
mad:click troca uma prop bool no servidor; mad-show reage no cliente sem precisar re-renderizar o componente.
Modo básico
Mostrando só o essencial.
Modo avançado
Detalhes extras liberados.
resources/views/tutor/examples/estrutura-reatividade/toggle.blade.php
<div @madWire(['modoAvancado'])>
<mad-btn variant="secondary" icon="toggle-left" mad:click="onToggleModo">Alternar modo</mad-btn>
<div mad-show="!modoAvancado" style="margin-top:.75rem;">
<mad-callout type="info" title="Modo básico">Mostrando só o essencial.</mad-callout>
</div>
<div mad-show="modoAvancado" style="margin-top:.75rem;">
<mad-callout type="success" title="Modo avançado">Detalhes extras liberados.</mad-callout>
</div>
</div>
app/control/Tutor/TutorEstruturaReatividade.php
public function onToggleModo(): void
{
$this->modoAvancado = !$this->modoAvancado;
}
Atualização parcial com html('#seletor')
MadResponse->html() substitui só o innerHTML do painel — o resto da tela fica intocado.
Painel inicial
Clique no botão para atualizar via MadResponse->html().
resources/views/tutor/examples/estrutura-reatividade/painel-parcial.blade.php
<div>
<mad-btn variant="primary" icon="refresh-cw" mad:click="onAtualizarPainel">Atualizar painel</mad-btn>
<div id="tutor-reativ-painel" style="margin-top:.75rem;">
<div class="mad-alert mad-alert-info">
<div class="mad-alert-title">Painel inicial</div>
<div class="mad-alert-desc">Clique no botão para atualizar via MadResponse->html().</div>
</div>
</div>
</div>
app/control/Tutor/TutorEstruturaReatividade.php
/**
* Atualização parcial via MadResponse->html() — substitui só o innerHTML
* do painel, sem re-renderizar o resto da página.
*/
public function onAtualizarPainel(): MadResponse
{
$agora = now()->format('H:i:s');
$sorte = random_int(1, 100);
$html = '<div class="mad-alert mad-alert-info">'
. '<div class="mad-alert-title">Painel atualizado</div>'
. '<div class="mad-alert-desc">Gerado às ' . e($agora) . ' — número da sorte: ' . $sorte . '</div>'
. '</div>';
return (new MadResponse())->html('#tutor-reativ-painel', $html);
}
Validação reativa em tempo real
mad:model sincroniza o valor, mad:change dispara a validação no servidor, e mad-show + mad-text exibem o erro sem re-render.
resources/views/tutor/examples/estrutura-reatividade/validacao.blade.php
@php
// $that (como $__component) e uma variavel LEXICAL setada por
// MadComponent::render() no template de TOPO da pagina. Este partial e
// incluido de dentro do componente Blade nativo tutor-demo (escopo
// isolado), entao $that nao chega ate aqui sozinho — precisa ser
// reobtido via o stack estatico de MadRenderContext (push/pop em
// MadComponent::render(), atravessa qualquer aninhamento de componentes).
$that = \Mad\Component\MadRenderContext::getComponent();
@endphp
<div @madWire(['erroEmail'])>
<label class="mad-label">E-mail</label>
<input class="mad-input" type="email" mad:model="emailReativo" mad:change="onValidarEmailReativo"
value="{{ $that->emailReativo }}" placeholder="seu@email.com">
<p class="mad-error" mad-show="erroEmail" mad-text="erroEmail" style="margin-top:.5rem;"></p>
</div>
app/control/Tutor/TutorEstruturaReatividade.php
/** Validação reativa disparada no mad:change do campo de e-mail. */
public function onValidarEmailReativo(): void
{
$email = trim($this->emailReativo);
$this->erroEmail = ($email === '' || filter_var($email, FILTER_VALIDATE_EMAIL) !== false)
? ''
: 'E-mail inválido.';
}
Código-fonte completo da página
app/control/Tutor/TutorEstruturaReatividade.php
<?php
namespace App\Control\Tutor;
use App\Support\Tutor\TutorPage;
use Mad\Http\MadResponse;
/**
* TutorEstruturaReatividade — página "Reatividade" do MAD Lab.
*
* Cobre o ciclo MadWire cliente↔servidor: two-way binding (mad:model[.live] +
* @madBind), estado reativo Alpine via @madWire + mad-text, visibilidade
* condicional via mad-show, atualização parcial de um ponto específico da
* tela via MadResponse->html(), e uma validação reativa combinando
* mad:model + mad:change + mad-show + mad-text. Nenhum demo usa <mad-form> —
* são componentes MadWire "soltos", exatamente como no gabarito das skills
* madwire-reactive-directives / madwire-twoway-binding.
*/
class TutorEstruturaReatividade extends TutorPage
{
protected string $catalogKey = 'estrutura_reatividade';
public string $nomeReativo = '';
public int $contador = 0;
public bool $modoAvancado = false;
public string $emailReativo = '';
public string $erroEmail = '';
/** Two-way binding puro: mad:model.live sincroniza sem chamar nenhuma action. */
public function onIncrementarContador(): void
{
$this->contador++;
}
public function onDecrementarContador(): void
{
$this->contador = max(0, $this->contador - 1);
}
public function onResetarContador(): void
{
$this->contador = 0;
}
public function onToggleModo(): void
{
$this->modoAvancado = !$this->modoAvancado;
}
/**
* Atualização parcial via MadResponse->html() — substitui só o innerHTML
* do painel, sem re-renderizar o resto da página.
*/
public function onAtualizarPainel(): MadResponse
{
$agora = now()->format('H:i:s');
$sorte = random_int(1, 100);
$html = '<div class="mad-alert mad-alert-info">'
. '<div class="mad-alert-title">Painel atualizado</div>'
. '<div class="mad-alert-desc">Gerado às ' . e($agora) . ' — número da sorte: ' . $sorte . '</div>'
. '</div>';
return (new MadResponse())->html('#tutor-reativ-painel', $html);
}
/** Validação reativa disparada no mad:change do campo de e-mail. */
public function onValidarEmailReativo(): void
{
$email = trim($this->emailReativo);
$this->erroEmail = ($email === '' || filter_var($email, FILTER_VALIDATE_EMAIL) !== false)
? ''
: 'E-mail inválido.';
}
}
resources/views/tutor/estrutura/reatividade.blade.php
<x-tutor-page page="estrutura_reatividade">
<x-tutor-demo demo="tutor.examples.estrutura-reatividade.two-way"
title="Two-way binding (mad:model.live + @madBind)"
desc="Input nativo sincroniza com a prop PHP a cada tecla (debounce), e @madBind reflete o valor sem re-renderizar a página." />
<x-tutor-demo demo="tutor.examples.estrutura-reatividade.contador"
title="Estado reativo com @madWire + mad-text"
desc="@madWire expõe props publicas como estado Alpine; mad-text reage a cada mudança vinda do servidor (mad:click)."
php="TutorEstruturaReatividade::onIncrementarContador" />
<x-tutor-demo demo="tutor.examples.estrutura-reatividade.toggle"
title="mad-show alternando conteúdo por estado"
desc="mad:click troca uma prop bool no servidor; mad-show reage no cliente sem precisar re-renderizar o componente."
php="TutorEstruturaReatividade::onToggleModo" />
<x-tutor-demo demo="tutor.examples.estrutura-reatividade.painel-parcial"
title="Atualização parcial com html('#seletor')"
desc="MadResponse->html() substitui só o innerHTML do painel — o resto da tela fica intocado."
php="TutorEstruturaReatividade::onAtualizarPainel" />
<x-tutor-demo demo="tutor.examples.estrutura-reatividade.validacao"
title="Validação reativa em tempo real"
desc="mad:model sincroniza o valor, mad:change dispara a validação no servidor, e mad-show + mad-text exibem o erro sem re-render."
php="TutorEstruturaReatividade::onValidarEmailReativo" />
</x-tutor-page>