Por que values existem: lendo configuração do DOM
O elemento de um controller Stimulus pode carregar configuração em atributos data-* comuns antes de o static values entrar em cena. this.element.dataset.dismissAfter lê uma string, sempre uma string, sem nome declarado para conferir erros de digitação e sem tipo para onde convertê-la. O controller de flash desta aplicação precisa de um número, e não de uma string, e o static values é o mecanismo que fecha essa lacuna.
Um controller que precisa de um número
app/javascript/controllers/ui/flash_controller.js, o value e o método que o lê:
export default class extends Controller {
static values = { dismissAfter: { type: Number, default: 0 } }
#scheduleAutoDismiss() {
if (this.dismissAfterValue <= 0) return
this.#dismissTimer = setTimeout(() => this.dismiss(), this.dismissAfterValue)
}
}
O setTimeout precisa de um número de milissegundos, e this.dismissAfterValue <= 0 é uma comparação numérica. Declarar dismissAfter como value Number faz o this.dismissAfterValue ser um número JavaScript toda vez que este método o lê. A conversão de string para número já aconteceu, num lugar em que este método nunca precisa pensar.
De onde vem o número
O app/views/layouts/_flash.html.erb renderiza o elemento a que este controller se liga:
data-ui--flash-dismiss-after-value="<%= duration_map.fetch(base_type, 5000) %>"
com duration_map = { "notice" => 4000, "alert" => 7000, "unlock" => 10000 }. Uma mensagem de sucesso fica 4 segundos na tela, um erro fica 7, e o aviso de conquista desbloqueada fica 10. O atributo HTML continua sendo texto: "4000" são dígitos dentro de uma string, como em qualquer atributo HTML. Os atributos HTML não mudaram. O que mudou é que o static values declara, uma vez, que o texto que cair nesse atributo chega ao this.dismissAfterValue já convertido em número.
O nome do atributo não é mais uma coisa para lembrar
dismissAfter (a propriedade JavaScript) e dismiss-after-value (o sufixo do atributo HTML) não são duas escolhas separadas. O Stimulus deriva o segundo do primeiro com uma transformação fixa: camelCase vira dash-case, e -value entra no fim. dismissAfter vira dismiss-after-value, e com o identificador do controller (ui--flash) na frente fica o data-ui--flash-dismiss-after-value completo que a partial desta aplicação escreve. Acerte o nome JavaScript e o nome HTML vem junto, sem um segundo nome para manter em sincronia à mão.
Sem static values
Ler o mesmo atributo à mão ficaria assim:
const raw = this.element.dataset.dismissAfter // "4000" — uma string, sempre
const ms = raw ? parseInt(raw, 10) : 0 // conversão, escrita à mão, toda vez
São duas linhas que o controller desta aplicação nunca escreve, repetidas em todo controller que lê um número do DOM, e cada chamada livre para escrever a conversão, o padrão ou o nome da propriedade de um jeito um pouco diferente. O static values transforma esse código repetido numa declaração. Dê o nome do value uma vez, diga o tipo uma vez, e todo controller que declara dismissAfter: Number ganha o mesmo comportamento, correto.
Pontos-chave
this.element.dataset.xxxsempre devolve uma string (ouundefined). Nada a converte, e nada confere se ela existe.- O
static valuesdeclara o nome e o tipo de um value uma vez. O Stimulus gera um acessor tipado (this.dismissAfterValue) que lê o atributo do DOM e o converte sozinho. - O controller de flash desta aplicação precisa do
dismissAfterValuecomo número para uma chamadasetTimeoute uma comparação<= 0, e um valueNumbergarante isso. - O nome do atributo HTML (
dismiss-after-value) vem do nome do value JavaScript (dismissAfter): dash-case mais o sufixo-value, com o identificador do controller na frente.
Continue com a aula 2
Declarando values: forma abreviada vs. forma completa de objeto
O atalho com só o tipo contra o objeto completo com tipo e padrão, com os cinco tipos em uso.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.