Uma biblioteca de clojurescript para fornecer ligações de dados de formulário para reagente, veja aqui uma demonstração ao vivo.
A biblioteca usa um átomo de reagente como o armazenamento de documentos. Os componentes estão vinculados ao documento usando o :field . Essa chave será usada para decidir como o tipo específico de componente deve ser vinculado. O componente também deve fornecer um atributo exclusivo :id que é usado para correlacioná -lo no documento. Enquanto a biblioteca é voltada para o uso com o Twitter Bootstrap, é bastante agnóstico sobre os tipos de componentes que você cria.
O :id pode ser uma palavra -chave, por exemplo: {:id :foo} ou um caminho com palavra -chave {:id :foo.bar} que mapeará para {:foo {:bar "value"}} . Como alternativa, você pode especificar um caminho vetorial explicitamente [:foo 0 :bar] .
Por padrão, o valor do componente é o do campo de documentos, no entanto, todos os componentes suportam atributos de função :in-fn e :out-fn . :in-fn aceita o valor atual do documento e retorna o que deve ser exibido no componente. :out-fn aceita o valor do componente e retorna o que deve ser armazenado no documento.
Os seguintes tipos de campos são suportados para fora da caixa:
Um campo de entrada pode ser do tipo :text , :numeric :range , :password , :email e :textarea . As entradas se comportam como as entradas HTML regulares e atualizam o estado do documento quando o evento :on-change é acionado.
[ :input.form-control { :field :text :id :first-name }]
[ :input.form-control { :field :numeric :id :age }] Os campos de entrada podem ter um atributo opcional :fmt que pode fornecer uma sequência de formato para o valor:
[ :input.form-control
{ :field :numeric :fmt " %.2f " :id :bmi :disabled true }]Entradas numéricas de suporte atributos para a entrada HTML 5 Número:
[ :input
{ :field :numeric
:id :volume
:fmt " %.2f "
:step " 0.1 "
:min 0
:max 10 }] O campo TypeAhead usa a tecla :data-source Bound a uma função que leva a entrada atual e retorna uma lista de resultados correspondentes. O controle usa um elemento de entrada para lidar com a entrada do usuário e renderiza a lista de opções como um elemento de lista não ordenado que contém um ou mais elementos de item da lista. Os usuários podem especificar as classes CSS usadas para renderizar cada um desses elementos usando as teclas: classe de entrada,: classe de listagem e: classe de item. Os usuários podem especificar adicionalmente uma classe CSS para lidar com o destaque da seleção atual com a tecla: Highlight-Class. As classes CSS de referência estão incluídas no arquivo Recursos/Public/CSS/Reagente-Forms.CSS.
( defn friend-source [text]
( filter
#( -> % ( .toLowerCase %) ( .indexOf text) ( > -1 ))
[ " Alice " " Alan " " Bob " " Beth " " Jim " " Jane " " Kim " " Rob " " Zoe " ]))
[ :div { :field :typeahead
:id :ta
:input-placeholder " pick a friend "
:data-source friend-source
:input-class " form-control "
:list-class " typeahead-list "
:item-class " typeahead-item "
:highlight-class " highlighted " }]O campo TypeAhead suporta a seleção de mouse e teclado.
Você pode fazer com que o valor exibido da entrada seja diferente do valor armazenado no documento. Você precisa especificar :out-fn , A :result-fn e, opcionalmente :in-fn . A :data-source precisa retornar um vetor [display-value stored-value] .
( defn people-source [people]
( fn [text]
( ->> people
( filter #( -> ( :name %)
( .toLowerCase )
( .indexOf text)
( > -1 )))
( mapv #( vector ( :name %) ( :num %))))))
[ :div { :field :typeahead
:data-source ( people-source people)
:in-fn ( fn [num]
[( :name ( first ( filter #( = num ( :num %)) people))) num])
:out-fn ( fn [[name num]] num)
:result-fn ( fn [[name num]] name)
:id :author.num }]]] Se :data-source responder com a lista completa de opções quando passada a palavra-chave :all , então a tecla de sepultura será exibida.
O atributo :selections pode ser especificado para passar por um átomo usado para manter as seleções. Isso oferece a opção de buscar a lista usando o TypeAhead Text - se um manipulador de resposta AJAX definir o átomo, a lista será lançada.
Se for fornecido, a função :get-index garantirá que o item selecionado seja destacado quando a lista é exibida.
Um exemplo completo está disponível no código -fonte da página de demonstração.
O campo da caixa de seleção cria um elemento de caixa de seleção:
[ :div.row
[ :div.col-md-2 " does data binding make you happy? " ]
[ :div.col-md-5
[ :input.form-control { :field :checkbox :id :happy-bindings }]]] A caixa de seleção aceita um atributo opcional :checked . Quando definido, a caixa de seleção será selecionada e o caminho do documento apontado pela tecla :id será definido como true .
[ :div.row
[ :div.col-md-2 " does data binding make you happy? " ]
[ :div.col-md-5
[ :input.form-control { :field :checkbox :id :happy-bindings :checked true }]]] O controle de faixa usa as teclas :min e :max para criar uma entrada de intervalo HTML:
[ :input.form-control
{ :field :range :min 10 :max 100 :id :some-range }] Os botões de rádio não usam a tecla :id pois devem ser únicos e, em vez disso, são agrupados usando o :name . O atributo :value é usado para indicar o valor que é salvo no documento:
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection }]
[ :input { :field :radio :value :c :name :radioselection }] O botão de rádio aceita um atributo opcional :checked . Quando definido, a caixa de seleção será selecionada e o caminho do documento apontado pela tecla :name será definido como true .
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection :checked true }]
[ :input { :field :radio :value :c :name :radioselection }] O campo do arquivo lança o objeto File de um <input type="file"/> .
[ :input { :field :file :type :file }] O mesmo que o arquivo, exceto que funciona com <input type="file" multiple/> e vincula todo o objeto FileList .
[ :input { :field :files :type :file :multiple true }] Os campos de lista contêm elementos filhos cujos valores são preenchidos no documento quando são selecionados. Os elementos filhos devem ter um atributo :key para o valor que será salvo no documento. O valor do elemento deve ser uma palavra -chave.
Os elementos podem ter um opcional :visible? palavra -chave que aponta para uma função de predicado. A função deve aceitar o documento e retornar um valor booleano indicando se o campo deve ser mostrado.
O campo :list é usado para criar elementos select HTML contendo option Child Elements:
[ :select.form-control { :field :list :id :many-options }
[ :option { :key :foo } " foo " ]
[ :option { :key :bar } " bar " ]
[ :option { :key :baz } " baz " ]]
( def months
[ " January " " February " " March " " April " " May " " June "
" July " " August " " September " " October " " November " " December " ])
[ :select { :field :list :id :dob.day }
( for [i ( range 1 32 )]
[ :option
{ :key ( keyword ( str i))
:visible? #( let [month ( get-in % [ :dob :month ])]
( cond
( < i 29 ) true
( < i 31 ) ( not= month :February )
( = i 31 ) ( some #{month} [ :January :March :May :July :August :October :December ])
:else false ))}
i])]
[ :select { :field :list :id :dob.month }
( for [month months]
[ :option { :key ( keyword month)} month])]
[ :select { :field :list :id :dob.year }
( for [i ( range 1950 ( inc ( .getFullYear ( js/Date. ))))]
[ :option { :key ( keyword ( str i))} i])]O campo de seleção única se comporta como a lista, mas suporta diferentes tipos de elementos e permite que os campos sejam desmarcados:
[ :h3 " single-select buttons " ]
[ :div.btn-group { :field :single-select :id :unique-position }
[ :button.btn.btn-default { :key :left } " Left " ]
[ :button.btn.btn-default { :key :middle } " Middle " ]
[ :button.btn.btn-default { :key :right } " Right " ]]
[ :h3 " single-select list " ]
[ :ul.list-group { :field :single-select :id :pick-one }
[ :li.list-group-item { :key :foo } " foo " ]
[ :li.list-group-item { :key :bar } " bar " ]
[ :li.list-group-item { :key :baz } " baz " ]]O campo de seleção múltipla permite que vários valores sejam selecionados e definidos no documento:
[ :h3 " multi-select list " ]
[ :div.btn-group { :field :multi-select :id :position }
[ :button.btn.btn-default { :key :left } " Left " ]
[ :button.btn.btn-default { :key :middle } " Middle " ]
[ :button.btn.btn-default { :key :right } " Right " ]] Os rótulos podem ser associados a uma chave no documento usando o atributo :id e exibirá o valor nessa chave. As Lables podem ter um opcional :preamble e :postamble Keys com o texto que será renderizado antes e depois do valor, respectivamente. O valor também pode ser interpretado usando uma função formatadora atribuída à tecla :fmt . A chave :placeholder pode ser usado para fornecer texto que será exibido na ausência de um valor:
[ :label { :field :label :id :volume }]
[ :label { :field :label :preamble " the value is: " :id :volume }]
[ :label { :field :label :preamble " the value is: " :postamble " ml " :id :volume }]
[ :label { :field :label :preamble " the value is: " :postamble " ml " :placeholder " N/A " :id :volume }]
[ :label { :field :label :preamble " the value is: " :id :volume :fmt ( fn [v] ( if v ( str v " ml " ) " unknown " )}] Os alertas estão vinculados a um ID de um campo que aciona o alerta e pode ter uma chave opcional :event . A chave do evento deve apontar para uma função que retorne um valor booleano.
Um opcional :closeable? true/false pode ser fornecido para controlar se um botão de fechamento deve ser renderizado (os padrões para TRUE).
Quando um evento é fornecido, o corpo do alerta é renderizado sempre que o evento retorna verdadeiro:
[ :input { :field :text :id :first-name }]
[ :div.alert.alert-success { :field :alert :id :last-name :event empty?} " first name is empty! " ]Quando nenhum evento é fornecido, o alerta é mostrado sempre que o valor no ID não estiver vazio e exibe o valor:
( def doc ( atom {}))
; ;define an alert that watches the `:errors.first-name` key for errors
[ :div.alert.alert-danger { :field :alert :id :errors.first-name }]
; ;trigger the alert by setting the error key
[ :button.btn.btn-default
{ :on-click
#( if ( empty? ( :first-name @doc))
( swap! doc assoc-in [ :errors :first-name ] " first name is empty! " ))}
" save " ][ :div { :field :datepicker :id :birthday :date-format " yyyy/mm/dd " :inline true }]A data é armazenada no documento usando o seguinte formato:
{ :year 2014 :month 11 :day 24 } O DatePicker também pode tomar um opcional :auto-close? Chave para indicar que deve ser fechada quando o dia for clicado. Isso padrão é false .
O formato da data pode ser definido usando a chave :date-format :
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " } O :date-format também pode apontar para uma função que retorna a data formatada:
{ :field :datepicker
:id :date
:date-format ( fn [{ :keys [year month day]}] ( str year " / " month " / " day))} O acima é útil em conjunto com a tecla :save-fn que permite fornecer uma função personalizada para salvar o valor. Por exemplo, se você quisesse usar um objeto JavaScript Date, poderá fazer o seguinte:
[ :div.input-group.date.datepicker.clickable
{ :field :datepicker
:id :reminder
:date-format ( fn [date]
( str ( .getDate date) " / "
( inc ( .getMonth date)) " / "
( .getFullYear date)))
:save-fn ( fn [current-date { :keys [year month day]}]
( if current-date
( doto ( js/Date. )
( .setFullYear year)
( .setMonth ( dec month))
( .setDate day)
( .setHours ( .getHours current-date))
( .setMinutes ( .getMinutes current-date)))
( js/Date. year ( dec month) day)))
:auto-close? true }]Observe que você precisa retornar um novo objeto de data em atualizações para o componente reagir.
DatePicker toma uma chave opcional :lang que você pode usar para definir o local do DatePicker. Atualmente, existem inglês, russo, alemão, francês, espanhol, português, finlandês e holandês construídos em traduções. Para usar um passe de idioma interno :lang com uma palavra-chave como na tabela a seguir:
| Linguagem | Palavra -chave |
|---|---|
| Inglês | :en-US (padrão) |
| russo | :ru-RU |
| Alemão | :de-DE |
| Francês | :fr-FR |
| Espanhol | :es-ES |
| Português | :pt-PT |
| finlandês | :fi-FI |
| Holandês | :nl-NL |
Exemplo de usar um local de idioma embutido:
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " :inline true :lang :ru-RU } Você também pode fornecer um mapa de hash de localidade personalizado para o DatePicker. :first-day marca o primeiro dia da semana a partir do domingo como 0. Todas as chaves devem ser especificadas.
Exemplo de usar um mapa de hash de localidade personalizada:
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " :inline true :lang
{ :days [ " First " " Second " " Third " " Fourth " " Fifth " " Sixth " " Seventh " ]
:days-short [ " 1st " " 2nd " " 3rd " " 4th " " 5th " " 6th " " 7th " ]
:months [ " Month-one " " Month-two " " Month-three " " Month-four " " Month-five " " Month-six "
" Month-seven " " Month-eight " " Month-nine " " Month-ten " " Month-eleven " " Month-twelve " ]
:months-short [ " M1 " " M2 " " M3 " " M4 " " M5 " " M6 " " M7 " " M8 " " M9 " " M10 " " M11 " " M12 " ]
:first-day 0 }} O DatePicker requer CSS adicional para ser renderizado corretamente. O CSS padrão é fornecido em reagent-forms.css no caminho dos recursos. Simplesmente verifique se está incluído na página. O arquivo pode ser lido usando:
( -> " reagent-forms.css " clojure.java.io/resource slurp)O elemento do contêiner pode ser usado para agrupar o elemento diferente. O contêiner pode ser usado para definir a visibilidade de vários elementos.
[ :div.form-group
{ :field :container
:visible? #( :show-name? %)}
[ :input { :field :text :id :first-name }]
[ :input { :field :text :id :last-name }]] Uma função de validador pode ser anexada a um componente usando a palavra -chave :validator . Esta função aceita o estado atual do documento e retorna uma coleção de classes que serão anexadas ao elemento:
[ :input
{ :field :text
:id :person.name.first
:validator ( fn [doc]
( when ( -> doc :person :name :first empty?)
[ " error " ]))}] Os componentes podem fornecer um opcional :visible? Chave em seus atributos que apontam para uma função de decisão. Espera -se que a função pegue o valor atual do documento e produza um valor verdadeiro que será usado para decidir se o componente deve ser renderizado, por exemplo:
( def form
[ :div
[ :input { :field :text
:id :foo }]
[ :input { :field :text
:visible? ( fn [doc] ( empty? ( :foo doc)))
:id :bar }]]) A tecla :set-attributes pode ser usada nos casos em que você precisa fazer uma atualização arbitrária sobre os atributos do componente. A chave deve apontar para uma função que aceita o valor atual do documento e o mapa dos atributos para o componente. A função deve retornar um mapa de atributo atualizado:
[ :div
[ :input { :field :text
:id :person.name.first
:validator ( fn [doc]
( when ( = " Bob " ( -> doc :person :name :first ))
[ " error " ]))}]
[ :input { :field :text
:id :person.name.last
:set-attributes ( fn [doc attrs]
( assoc attrs :disabled ( = " Bob " ( -> doc :person :name :first ))))}]]O exemplo acima desativa a entrada do sobrenome quando o valor da entrada de primeiro nome é "Bob".
Os componentes de campo se comportam como qualquer outro componente de reagente e podem ser misturados com eles livremente. Um exemplo de formulário completo pode ser visto abaixo.
Os elementos de formulário podem ser vinculados a uma estrutura aninhada usando o . como um separador de caminho. Por exemplo, o seguinte componente [:input {:field :text :id :person.first-name}] se liga ao seguinte caminho no átomo de estado {:person {:first-name <field-value>}}
( defn row [label input]
[ :div.row
[ :div.col-md-2 [ :label label]]
[ :div.col-md-5 input]])
( def form-template
[ :div
( row " first name " [ :input { :field :text :id :first-name }])
( row " last name " [ :input { :field :text :id :last-name }])
( row " age " [ :input { :field :numeric :id :age }])
( row " email " [ :input { :field :email :id :email }])
( row " comments " [ :textarea { :field :textarea :id :comments }])])nota importante
Os modelos são avaliados ansiosamente e você deve sempre chamar as funções do ajudante, como no exemplo acima, em vez de colocá -las em um vetor. Estes serão substituídos pelos componentes do reagente quando os bind-fields forem chamados para compilar o modelo.
Depois que um modelo de formulário é criado, ele pode ser vinculado a um documento usando a função bind-fields :
( ns myform.core
( :require [reagent-forms.core :refer [bind-fields]]
[reagent.core :as r]))
( defn form []
( let [doc ( r/atom {})]
( fn []
[ :div
[ :div.page-header [ :h1 " Reagent Form " ]]
[bind-fields form-template doc]
[ :label ( str @doc)]])))
( reagent/render-component [form] ( .getElementById js/document " container " ))O formulário pode ser inicializado com um documento povoado, e os campos serão inicializados com os valores encontrados lá:
( def form-template
[ :div
( row " first name "
[ :input.form-control { :field :text :id :first-name }])
( row " last name "
[ :input.form-control { :field :text :id :last-name }])
( row " age "
[ :input.form-control { :field :numeric :id :age }])
( row " email "
[ :input.form-control { :field :email :id :email }])
( row " comments "
[ :textarea.form-control { :field :textarea :id :comments }])])
( defn form []
( let [doc ( atom { :first-name " John " :last-name " Doe " :age 35 })]
( fn []
[ :div
[ :div.page-header [ :h1 " Reagent Form " ]]
[bind-fields form-template doc]
[ :label ( str @doc)]]))) A função bind-fields aceita eventos opcionais. Os eventos são acionados sempre que o documento for atualizado e será executado na ordem em que estão listados. Cada evento vê o documento modificado por seu antecessor.
O evento deve levar 3 parâmetros, que são o id , o path , o value e o document . O id corresponde ao :id do campo, o path é o caminho do campo no documento, o value representa o valor que foi alterado no formulário e o documento contém o estado do formulário. O evento pode retornar um documento atualizado ou nil , quando nil é retornado, o estado do documento não é modificado.
A seguir, é apresentado um exemplo de um evento para calcular o valor da :bmi quando o :weight e :height são preenchidas:
( defn row [label input]
[ :div.row
[ :div.col-md-2 [ :label label]]
[ :div.col-md-5 input]])
( def form-template
[ :div
[ :h3 " BMI Calculator " ]
( row " Height " [ :input { :field :numeric :id :height }])
( row " Weight " [ :input { :field :numeric :id :weight }])
( row " BMI " [ :input { :field :numeric :id :bmi :disabled true }])])
[bind-fields
form-template
doc
( fn [id path value { :keys [weight height] :as doc}]
( when ( and ( some #{id} [ :height :weight ]) weight height)
( assoc-in doc [ :bmi ] ( / weight ( * height height)))))] Você pode fornecer um mapa personalizado das funções de eventos aos bind-fields para usar formulários de reagentes com uma biblioteca como re-frame . Nesse caso, as formas de reagentes não manterão nenhum estado e funções internas fornecidas por você serão usadas para obter, salvar e atualizar o valor do campo. Aqui está um exemplo:
( ns foo.bar
( :require [re-frame.core :as re-frame]
[reagent-forms.core :refer [bind-fields]]))
; re-frame events
( re-frame/reg-event-db
:init
( fn [_ _]
{ :doc {}}))
( re-frame/reg-sub
:doc
( fn [db _]
( :doc db)))
( re-frame/reg-sub
:value
:<- [ :doc ]
( fn [doc [_ path]]
( get-in doc path)))
( re-frame/reg-event-db
:set-value
( fn [db [_ path value]]
( assoc-in db ( into [ :doc ] path) value)))
( re-frame/reg-event-db
:update-value
( fn [db [_ f path value]]
( update-in db ( into [ :doc ] path) f value)))
; Functions that will be called by each individual form field with an id and a value
( def events
{ :get ( fn [path] @( re-frame/subscribe [ :value path]))
:save! ( fn [path value] ( re-frame/dispatch [ :set-value path value]))
:update! ( fn [path save-fn value]
; save-fn should accept two arguments: old-value, new-value
( re-frame/dispatch [ :update-value save-fn path value]))
:doc ( fn [] @( re-frame/subscribe [ :doc ]))})
; bind-fields called with a form and a map of custom events
( defn foo
[]
[bind-fields
[ :div
[ :input { :field :text
:id :person.name.first
:valid? ( fn [doc]
( when ( = " Bob " ( -> doc :person :name :first ))
[ " error " ]))}]
[ :input { :field :text
:id :person.name.last }]]
events])A visibilidade do elemento pode ser definida fornecendo o ID em um documento que será tratado como um valor verdadeiro ou uma função:
( re-frame/reg-event-db
:toggle-foo
( fn [db _]
( update-in db [ :doc :foo ] not)))
( re-frame/reg-sub
:bar-visible?
( fn [db _]
( :bar db)))
( re-frame/reg-event-db
:toggle-bar
( fn [db _]
( update db :bar not)))
( def form
[ :div
[ :input { :field :text
:id :foo-input
:visible? :foo }]
[ :input { :field :text
:id :bar-input
:visible? ( fn [doc] @( re-frame/subscribe [ :bar-visible? ]))}]
( defn page
[]
[ :div
[bind-fields
[ :input { :field :text
:id :foo-input
:visible? :foo-input-visible? }]
event-fns]
[ :button
{ :on-click #( re-frame/dispatch [ :toggle-foo ])}
" toggle foo " ]
[ :button
{ :on-click #( re-frame/dispatch [ :toggle-bar ])}
" toggle bar " ]])Se você estiver usando o re-quadro, é recomendável que você use eventos de re-quadro para acionar o recálculo de campos no formulário. Por exemplo, vamos dar uma olhada em um campo de IMC calculado:
( re-frame/reg-sub
:value
:<- [ :doc ]
( fn [doc [_ path]]
( get-in doc path)))
( defn bmi [{ :keys [weight height] :as doc}]
( assoc doc :bmi ( / weight ( * height height))))
( defmulti rule ( fn [_ path _] path))
( defmethod rule [ :height ] [doc path value]
( bmi doc))
( defmethod rule [ :weight ] [doc path value]
( bmi doc))
( defmethod rule :default [doc path value]
doc )
( re-frame/reg-event-db
:set-value
( fn [{ :keys [doc] :as db} [_ path value]]
( -> db
( assoc-in ( into [ :doc ] path) value)
( update :doc rule path value))))
( def events
{ :get ( fn [path] @( re-frame/subscribe [ :value path]))
:save! ( fn [path value] ( re-frame/dispatch [ :set-value path value]))
:doc ( fn [] @( re-frame/subscribe [ :doc ]))})
( defn row [label input]
[ :div
[ :div [ :label label]]
[ :div input]])
( def form-template
[ :div
[ :h3 " BMI Calculator " ]
( row " Height " [ :input { :field :numeric :id :height }])
( row " Weight " [ :input { :field :numeric :id :weight }])
( row " BMI " [ :label { :field :label :id :bmi }])])
( defn home-page []
[ :div
[ :h2 " BMI example " ]
[bind-fields form-template events]]) A rule Multiemthod será acionada quando o evento :set-value for chamado e calcular o IMC sempre que a altura ou peso for atualizado.
Os campos personalizados podem ser adicionados implementando o Multimethod reagent-forms.core/init-field . O método deve levar dois parâmetros, onde o primeiro parâmetro é o componente de campo e o segundo são as opções.
Por padrão, as opções conterão o get e o save! , e update! chaves. O get KEY aponta para uma função que aceita um ID e retorna o valor do documento associado a ele. O save! A função aceita um ID e um valor que estará associado a ele. A update! A função aceita um ID, uma função que lidará com a atualização e o valor. O manuseio de funções da atualização receberá os antigos e os novos valores.
Os adaptadores podem ser fornecidos aos campos para criar formatos de armazenamento personalizados para valores de campo. Estas são um par de funções passadas para o campo através das teclas :in-fn e :out-fn . :in-fn modifica o item armazenado para que o campo possa usá-lo enquanto :out-fn modifica a saída do campo antes de ser armazenado. Por exemplo, para usar um objeto js/Date nativo como o formato de armazenamento, o DatePicker pode ser inicializado assim:
[ :div { :field :datepicker :id :birthday :date-format " yyyy/mm/dd " :inline true
:in-fn #( when % { :year ( .getFullYear %) :month ( .getMonth %) :day ( .getDate %)})
:out-fn #( when % ( js/Date ( :year %) ( :month %) ( :day %)))}]Os adaptadores podem ser passados nulos para que eles sejam capazes de lidar com eles.
O Safari no iOS terá um atraso de 300ms para :on-click , é possível definir um evento de gatilho personalizado usando a chave :touch-event . Veja aqui a lista de eventos disponíveis no React. Por exemplo, se quiséssemos usar :on-touch-start em vez de :on-click para acionar o evento, poderíamos fazer o seguinte:
[ :input.form-control { :field :text :id :first-name :touch-event :on-touch-start }] Observe que você também terá que definir o estilo de cursor: pointer para outros elementos que não sejam botões para que os eventos funcionem no iOS.
O TapeventPlugin for React é outra opção para criar eventos responsivos, até que a funcionalidade se torne disponível no React em si.
Este projeto usa Doo para executar os testes. Você deve instalar um dos ambientes suportados por DOO, consulte os documentos para obter detalhes. Para executar os testes, por exemplo, usando o Phantom, faça:
lein doo slimer test
Copyright © 2018 Dmitri Sotnikov
Distribuído sob a licença pública Eclipse, versão 1.0 ou (por sua opção) qualquer versão posterior.