Por que values existem: lendo configuração do DOM

Prévia grátis 3 min de leitura

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.xxx sempre devolve uma string (ou undefined). Nada a converte, e nada confere se ela existe.
  • O static values declara 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 dismissAfterValue como número para uma chamada setTimeout e uma comparação <= 0, e um value Number garante 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.
Aula 1 de 7 · grátis

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.

Digite para buscar...