MAD Lab
/
Tutor > Estrutura de formulário > Reatividade

Reatividade

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>&#64;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-&gt;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>