Formulários
Trabalhando com formulários
Section titled “Trabalhando com formulários”O Slash fornece helpers tipados para trabalhar com formulários de forma simples e eficiente. Não há “magia” - você usa HTML nativo e adiciona reatividade com createState() e os helpers de form.
Abordagens disponíveis
Section titled “Abordagens disponíveis”- Manual: Controle total usando
createState()e event handlers - Two-way binding: Helpers para sincronização automática (ex:
textFieldControl) - Form data: Extrair dados do form com
formToObject()eonSubmit()
Formulário básico (manual)
Section titled “Formulário básico (manual)”A forma mais simples é usar createState() e event handlers:
import { html, createState } from '@ezbug/slash'
function LoginForm() { const form = createState({ email: '', password: '' })
const handleSubmit = (e: Event) => { e.preventDefault() const data = form.get() console.log('Login:', data) }
return html` <form onSubmit=${handleSubmit}> <div> <label>Email:</label> <input type="email" value=${form.get().email} onInput=${(e: Event) => { const current = form.get() form.set({ ...current, email: (e.target as HTMLInputElement).value }) }} /> </div>
<div> <label>Senha:</label> <input type="password" value=${form.get().password} onInput=${(e: Event) => { const current = form.get() form.set({ ...current, password: (e.target as HTMLInputElement).value }) }} /> </div>
<button type="submit">Entrar</button> </form> `}Two-way binding com helpers
Section titled “Two-way binding com helpers”O Slash fornece helpers para binding automático:
textFieldControl - Text inputs e textareas
Section titled “textFieldControl - Text inputs e textareas”import { html, createState } from '@ezbug/slash'import { textFieldControl } from '@ezbug/slash'
function TextForm() { const nameState = createState({ value: '' }) const bioState = createState({ value: '' })
// Control para <input> const nameControl = textFieldControl(nameState, 'input')
// Control para <textarea> const bioControl = textFieldControl(bioState, 'input')
return html` <form> <div> <label>Nome:</label> <input type="text" ...${nameControl} /> </div>
<div> <label>Bio:</label> <textarea ...${bioControl}></textarea> </div>
<p>Nome: ${nameState.get().value}</p> <p>Bio: ${bioState.get().value}</p> </form> `}Modos de controle
Section titled “Modos de controle”textFieldControl aceita três modos:
| Modo | Quando atualiza | Use quando |
|---|---|---|
"input" | A cada tecla digitada | Feedback instantâneo (default) |
"change" | Ao sair do campo (blur) | Validação menos frequente |
"both" | Nos dois eventos | Máxima compatibilidade |
// Input mode (default)const ctrl1 = textFieldControl(state, 'input')
// Change modeconst ctrl2 = textFieldControl(state, 'change')
// Ambosconst ctrl3 = textFieldControl(state, 'both')checkboxControl - Checkboxes
Section titled “checkboxControl - Checkboxes”import { html, createState } from '@ezbug/slash'import { checkboxControl } from '@ezbug/slash'
function TermsForm() { const termsState = createState({ value: false }) const newsState = createState({ value: true })
const termsCtrl = checkboxControl(termsState) const newsCtrl = checkboxControl(newsState)
return html` <form> <label> <input type="checkbox" ...${termsCtrl} /> Aceito os termos </label>
<label> <input type="checkbox" ...${newsCtrl} /> Receber newsletter </label>
<p>Termos aceitos: ${termsState.get().value ? 'Sim' : 'Não'}</p> <p>Newsletter: ${newsState.get().value ? 'Sim' : 'Não'}</p> </form> `}radioControl - Radio buttons
Section titled “radioControl - Radio buttons”import { html, createState } from '@ezbug/slash'import { radioControl } from '@ezbug/slash'
function PreferenceForm() { const themeState = createState({ value: 'light' })
const lightCtrl = radioControl(themeState, 'light') const darkCtrl = radioControl(themeState, 'dark') const autoCtrl = radioControl(themeState, 'auto')
return html` <form> <p>Escolha o tema:</p>
<label> <input type="radio" name="theme" ...${lightCtrl} /> Claro </label>
<label> <input type="radio" name="theme" ...${darkCtrl} /> Escuro </label>
<label> <input type="radio" name="theme" ...${autoCtrl} /> Automático </label>
<p>Tema selecionado: ${themeState.get().value}</p> </form> `}SelectControl - Select dropdowns
Section titled “SelectControl - Select dropdowns”import { html, createState } from '@ezbug/slash'import { SelectControl } from '@ezbug/slash'
function CountryForm() { const countryState = createState({ value: 'br' }) const countryCtrl = SelectControl(countryState)
return html` <form> <label> País: <select ...${countryCtrl}> <option value="br">Brasil</option> <option value="us">Estados Unidos</option> <option value="pt">Portugal</option> <option value="es">Espanha</option> </select> </label>
<p>País selecionado: ${countryState.get().value}</p> </form> `}Form data helpers
Section titled “Form data helpers”formToObject - Extrair dados do form
Section titled “formToObject - Extrair dados do form”Converte um <form> em um objeto JavaScript:
import { formToObject } from '@ezbug/slash'
const form = document.querySelector('form')!const data = formToObject(form)
console.log(data)// { email: "user@example.com", password: "secret", terms: "on" }onSubmit - Handler de submit simplificado
Section titled “onSubmit - Handler de submit simplificado”Previne o default e extrai dados automaticamente:
import { html } from '@ezbug/slash'import { onSubmit } from '@ezbug/slash'
function ContactForm() { const handleSubmit = onSubmit((data, e) => { console.log('Dados:', data) // data = { name: "...", email: "...", message: "..." }
// Fazer POST para API fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) }) })
return html` <form onSubmit=${handleSubmit}> <input type="text" name="name" placeholder="Nome" /> <input type="email" name="email" placeholder="Email" /> <textarea name="message" placeholder="Mensagem"></textarea> <button type="submit">Enviar</button> </form> `}Validação
Section titled “Validação”O Slash não possui um sistema de validação built-in, mas você pode criar facilmente com createState():
Validação básica
Section titled “Validação básica”import { html, createState } from '@ezbug/slash'
function SignupForm() { const form = createState({ email: '', password: '', errors: { email: '', password: '' } })
const validate = () => { const state = form.get() const errors = { email: '', password: '' }
// Validar email if (!state.email) { errors.email = 'Email é obrigatório' } else if (!state.email.includes('@')) { errors.email = 'Email inválido' }
// Validar senha if (!state.password) { errors.password = 'Senha é obrigatória' } else if (state.password.length < 6) { errors.password = 'Senha deve ter no mínimo 6 caracteres' }
form.set({ ...state, errors })
return !errors.email && !errors.password }
const handleSubmit = (e: Event) => { e.preventDefault()
if (validate()) { console.log('Formulário válido!', form.get()) } }
return html` <form onSubmit=${handleSubmit}> <div> <input type="email" placeholder="Email" value=${form.get().email} onInput=${(e: Event) => { const state = form.get() form.set({ ...state, email: (e.target as HTMLInputElement).value, errors: { ...state.errors, email: '' } }) }} /> ${form.get().errors.email && html`<span class="error">${form.get().errors.email}</span>`} </div>
<div> <input type="password" placeholder="Senha" value=${form.get().password} onInput=${(e: Event) => { const state = form.get() form.set({ ...state, password: (e.target as HTMLInputElement).value, errors: { ...state.errors, password: '' } }) }} /> ${form.get().errors.password && html`<span class="error">${form.get().errors.password}</span>`} </div>
<button type="submit">Cadastrar</button> </form> `}Validação assíncrona
Section titled “Validação assíncrona”import { html, createState } from '@ezbug/slash'
function UsernameForm() { const state = createState({ username: '', checking: false, error: '' })
const checkUsername = async (username: string) => { state.set({ ...state.get(), checking: true, error: '' })
try { const res = await fetch(`/api/check-username?name=${username}`) const { available } = await res.json()
state.set({ ...state.get(), checking: false, error: available ? '' : 'Username já existe' }) } catch (err) { state.set({ ...state.get(), checking: false, error: 'Erro ao verificar' }) } }
return html` <form> <input type="text" placeholder="Username" value=${state.get().username} onInput=${(e: Event) => { const username = (e.target as HTMLInputElement).value state.set({ ...state.get(), username }) }} onBlur=${() => { const username = state.get().username if (username) checkUsername(username) }} />
${state.get().checking && html`<span>Verificando...</span>`} ${state.get().error && html`<span class="error">${state.get().error}</span>`} </form> `}Tipos de eventos de formulário
Section titled “Tipos de eventos de formulário”O Slash exporta tipos completos para todos os eventos de formulário:
import type { TextFieldEvent, CheckboxEvent, RadioEvent, SelectEvent, FormSubmitEvent, FormResetEvent, ButtonEvent} from '@ezbug/slash'
// Text field (input/textarea)function handleInput(e: TextFieldEvent) { console.log(e.target.value)}
// Checkboxfunction handleCheck(e: CheckboxEvent) { console.log(e.target.checked)}
// Radiofunction handleRadio(e: RadioEvent) { console.log(e.target.value, e.target.checked)}
// Selectfunction handleSelect(e: SelectEvent) { console.log(e.target.value)}
// Form submitfunction handleSubmit(e: FormSubmitEvent) { e.preventDefault() console.log(e.currentTarget) // HTMLFormElement}Helpers de extração de valor
Section titled “Helpers de extração de valor”Funções utilitárias para extrair valores de eventos:
import { getText, getChecked, getSelectValue } from '@ezbug/slash'
// Text fieldconst handleInput = (e: TextFieldEvent) => { const value = getText(e) // string console.log(value)}
// Checkbox/Radioconst handleCheck = (e: CheckboxEvent) => { const checked = getChecked(e) // boolean console.log(checked)}
// Selectconst handleSelect = (e: SelectEvent) => { const value = getSelectValue(e) // string console.log(value)}Próximos passos
Section titled “Próximos passos”- Error Handling - Tratamento de erros
- Componentes - Criando form components reutilizáveis
- Estado - Gerenciamento de estado avançado