Una biblioteca Clojurescript Para proporcionar enlaces de datos de formulario para reactivos, consulte aquí para una demostración en vivo.
La biblioteca utiliza un átomo de reactivo como tienda de documentos. Los componentes están vinculados al documento utilizando el atributo :field :. Esta clave se utilizará para decidir cómo debe estar unido el tipo específico de componente. El componente también debe proporcionar un atributo único :id que se utiliza para correlacionarlo con el documento. Si bien la biblioteca está orientada al uso con Bootstrap de Twitter, es bastante agnóstico sobre los tipos de componentes que crea.
El :id puede ser una palabra clave, por ejemplo: {:id :foo} , o una ruta de palabras clave {:id :foo.bar} que se asignará a {:foo {:bar "value"}} . Alternativamente, puede especificar una ruta vectorial explícitamente [:foo 0 :bar] .
De forma predeterminada, el valor del componente es el del campo de documento, sin embargo, todos los componentes admiten :in-fn y :out-fn . :in-fn acepta el valor actual del documento y devuelve lo que se mostrará en el componente. :out-fn acepta el valor del componente y devuelve lo que se almacenará en el documento.
Los siguientes tipos de campos son compatibles con la caja:
Un campo de entrada puede ser de tipo :text , :numeric , :range , :password :email y :textarea . Las entradas se comportan al igual que las entradas HTML regulares y actualizan el estado del documento cuando se activa el evento :on-change .
[ :input.form-control { :field :text :id :first-name }]
[ :input.form-control { :field :numeric :id :age }] Los campos de entrada pueden tener un atributo opcional :fmt que puede proporcionar una cadena de formato para el valor:
[ :input.form-control
{ :field :numeric :fmt " %.2f " :id :bmi :disabled true }]Las entradas numéricas son atributos de soporte para la entrada del número HTML 5:
[ :input
{ :field :numeric
:id :volume
:fmt " %.2f "
:step " 0.1 "
:min 0
:max 10 }] El campo TypeAhead utiliza una tecla :data-source vinculada a una función que toma la entrada actual y devuelve una lista de resultados coincidentes. El control utiliza un elemento de entrada para manejar la entrada del usuario y representa la lista de opciones como un elemento de lista no ordenado que contiene uno o más elementos de elementos de lista. Los usuarios pueden especificar las clases CSS utilizadas para representar cada uno de estos elementos utilizando las teclas: Input-Class ,: List-Class y: Element-Class. Los usuarios también pueden especificar una clase CSS para manejar la resaltación de la selección actual con la tecla: Class de resaltado. Las clases de referencia CSS se incluyen en el archivo recursos/público/css/reagent-formss.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 " }]El campo Typeahead admite la selección del mouse y del teclado.
Puede hacer que el valor mostrado de la entrada sea diferente al valor almacenado en el documento. Debe especificar :out-fn , A :result-fn y opcionalmente :in-fn . La :data-source debe devolver un vector [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 }]]] IF :data-source responde con la lista de opciones completa cuando se pasa la palabra clave :all las teclas de flujo baja mostrarán la lista.
El atributo :selections se puede especificar para pasar un átomo utilizado para contener las selecciones. Esto le da la opción de obtener la lista usando el texto Typeehead: si un controlador de respuesta AJAX establece el átomo de la lista.
Si se suministra, la función :get-index se asegurará de que el elemento seleccionado se resalte cuando la lista se presente.
Un ejemplo completo está disponible en el código fuente para la página de demostración.
El campo de la casilla de verificación crea un elemento de casilla de verificación:
[ :div.row
[ :div.col-md-2 " does data binding make you happy? " ]
[ :div.col-md-5
[ :input.form-control { :field :checkbox :id :happy-bindings }]]] La casilla de verificación acepta un atributo opcional :checked . Cuando se establece, se seleccionará la casilla de verificación y la ruta del documento apuntada por la tecla :id se establecerá en 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 }]]] El control de rango utiliza :min y :max para crear una entrada de rango HTML:
[ :input.form-control
{ :field :range :min 10 :max 100 :id :some-range }] Los botones de radio no usan la tecla :id ya que debe ser única y, en cambio, se agrupan utilizando el atributo :name . El atributo :value se usa para indicar el valor que se guarda en el documento:
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection }]
[ :input { :field :radio :value :c :name :radioselection }] El botón de radio acepta un atributo opcional :checked . Cuando se establece, se seleccionará la casilla de verificación y la ruta del documento señaló por la tecla :name se establecerá en true .
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection :checked true }]
[ :input { :field :radio :value :c :name :radioselection }] El campo Archivo vincula el objeto File de un <input type="file"/> .
[ :input { :field :file :type :file }] Igual que el archivo, excepto que funciona con <input type="file" multiple/> y vincula todo el objeto FileList .
[ :input { :field :files :type :file :multiple true }] Los campos de la lista contienen elementos infantiles cuyos valores están poblados en el documento cuando se seleccionan. Los elementos infantiles deben tener cada uno :key que apunte al valor que se guardará en el documento. El valor del elemento debe ser una palabra clave.
Los elementos pueden tener una opcional :visible? Palabra clave que apunta a una función de predicado. La función debe aceptar el documento y devolver un valor booleano que indique si se debe mostrar el campo.
El campo :list se utiliza para crear elementos select HTML que contienen option elementos infantiles:
[ :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])]El campo de selección única se comporta como la lista, pero admite diferentes tipos de elementos y permite que los campos sean deseleccionados:
[ :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 " ]]El campo multiselecto permite seleccionar y establecer múltiples valores en el 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 " ]] Las etiquetas pueden asociarse con una clave en el documento utilizando el atributo :id y mostrarán el valor en esa clave. Las Lables pueden tener una opcional :preamble y :postamble Keys con el texto que se representará antes y después del valor respectivamente. El valor también se puede interpretar utilizando una función Formatter asignada a la tecla :fmt . La clave :placeholder se puede usar para proporcionar un texto que se mostrará en ausencia de un 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 " )}] Las alertas están vinculadas a una ID de un campo que desencadena la alerta y puede tener una clave opcional :event . La clave del evento debe apuntar a una función que devuelva un valor booleano.
Una opcional :closeable? true/false se puede proporcionar para controlar si se debe representar un botón de cierre (predeterminado es verdadero).
Cuando se suministra un evento, el cuerpo de la alerta se representa cada vez que el evento devuelve verdadero:
[ :input { :field :text :id :first-name }]
[ :div.alert.alert-success { :field :alert :id :last-name :event empty?} " first name is empty! " ]Cuando no se suministra ningún evento, la alerta se muestra cada vez que el valor en la ID no está vacío y muestra el 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 }]La fecha se almacena en el documento utilizando el siguiente formato:
{ :year 2014 :month 11 :day 24 } DatePicker también puede tomar una opcional :auto-close? clave para indicar que debe cerrarse cuando se haga clic en el día. Este valor predeterminado es false .
El formato de fecha se puede establecer utilizando la clave :date-format :
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " } El :date-format también puede señalar una función que devuelve la fecha formateada:
{ :field :datepicker
:id :date
:date-format ( fn [{ :keys [year month day]}] ( str year " / " month " / " day))} Lo anterior es útil junto con la tecla :save-fn que le permite proporcionar una función personalizada para guardar el valor. Por ejemplo, si desea usar un objeto de fecha JavaScript, puede hacer lo siguiente:
[ :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 }]Tenga en cuenta que debe devolver un nuevo objeto de fecha en las actualizaciones para el componente para volver a pintar.
DatePicker toma una clave opcional :lang que puede usar para establecer la ubicación del DatePicker. Actualmente hay traducciones integradas en inglés, ruso, alemán, francés, español, portugués, finlandés y holandés. Para usar un lenguaje incorporado Pase en :lang con una palabra clave como en la siguiente tabla:
| Idioma | Palabra clave |
|---|---|
| Inglés | :en-US (predeterminado) |
| ruso | :ru-RU |
| Alemán | :de-DE |
| Francés | :fr-FR |
| Español | :es-ES |
| portugués | :pt-PT |
| finlandés | :fi-FI |
| Holandés | :nl-NL |
Ejemplo de uso de un local de lenguaje incorporado:
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " :inline true :lang :ru-RU } También puede proporcionar un mapa hash localizado para el mapa de fecha. :first-day marca el primer día de la semana a partir del domingo como 0. Todas las llaves deben especificarse.
Ejemplo del uso de un mapa hash localizado:
{ :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 }} DatePicker requiere CSS adicional para que se presente correctamente. El CSS predeterminado se proporciona en reagent-forms.css en la ruta de recursos. Simplemente asegúrese de que esté incluido en la página. El archivo se puede leer usando:
( -> " reagent-forms.css " clojure.java.io/resource slurp)El elemento contenedor se puede usar para agrupar un elemento diferente. El contenedor se puede usar para establecer la visibilidad de múltiples elementos.
[ :div.form-group
{ :field :container
:visible? #( :show-name? %)}
[ :input { :field :text :id :first-name }]
[ :input { :field :text :id :last-name }]] Se puede conectar una función de validador a un componente utilizando la palabra clave :validator . Esta función acepta el estado actual del documento y devuelve una colección de clases que se agregarán al elemento:
[ :input
{ :field :text
:id :person.name.first
:validator ( fn [doc]
( when ( -> doc :person :name :first empty?)
[ " error " ]))}] Los componentes pueden suministrar una opcional :visible? clave en sus atributos que apuntan a una función de decisión. Se espera que la función tome el valor actual del documento y produzca un valor de verdad que se utilizará para decidir si el componente debe ser representado, por ejemplo:
( def form
[ :div
[ :input { :field :text
:id :foo }]
[ :input { :field :text
:visible? ( fn [doc] ( empty? ( :foo doc)))
:id :bar }]]) La tecla :set-attributes se puede usar en los casos en que necesita hacer una actualización arbitraria sobre los atributos del componente. La clave debe apuntar a una función que acepte el valor actual del documento y el mapa de los atributos para el componente. La función debe devolver un mapa de atributos actualizado:
[ :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 ))))}]]El ejemplo anterior deshabilita la entrada de apellido cuando el valor de la entrada de primer nombre es "Bob".
Los componentes de campo se comportan al igual que cualquier otro componente de reactivo y se pueden mezclar con ellos libremente. A continuación se puede ver un ejemplo de formulario completo.
Los elementos de formulario se pueden unir a una estructura anidada utilizando el . como un separador de ruta. Por ejemplo, el siguiente componente [:input {:field :text :id :person.first-name}] se une a la siguiente ruta en el estado 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
Las plantillas se evalúan ansiosamente, y siempre debe llamar a las funciones de ayuda como en el ejemplo anterior en lugar de ponerlas en un vector. Estos serán reemplazados por componentes de reactivos cuando se llame a los bind-fields para compilar la plantilla.
Una vez que se crea una plantilla de formulario, se puede vincular a un documento utilizando la función 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 " ))El formulario se puede inicializar con un documento poblado, y los campos se inicializarán con los valores encontrados allí:
( 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)]]))) La función bind-fields acepta eventos opcionales. Los eventos se activan cuando se actualiza el documento y se ejecutará en el orden en que se enumeran. Cada evento ve el documento modificado por su predecesor.
El evento debe tomar 3 parámetros, que son la id , la path , el value y el document . La id coincide con :id del campo, la path es la ruta del campo en el documento, el value representa el valor que se cambió en el formulario y el documento contiene el estado del formulario. El evento puede devolver un documento actualizado o nil , cuando se devuelve nil , entonces el estado del documento no está modificado.
El siguiente es un ejemplo de un evento para calcular el valor de la tecla :bmi cuando las teclas :weight y :height están pobladas:
( 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)))))] Puede proporcionar un mapa personalizado de funciones de eventos a bind-fields para usar formas de reactivos con una biblioteca como re-frame . En ese caso, las formas de reactivos no tendrán ningún estado interno y funciones proporcionadas por usted, se utilizará para obtener, guardar y actualizar el valor del campo. Aquí hay un ejemplo:
( 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])La visibilidad del elemento se puede establecer proporcionando la identificación en un documento que se tratará como un valor verdadero o una función:
( 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 " ]])Si está utilizando el reframo, se recomienda que use eventos de reframo para activar la recalculación de campos en el formulario. Por ejemplo, echemos un vistazo a un 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]]) La rule MultiemThod se activará cuando se llame al evento :set-value , y calculará el IMC cada vez que se actualice la altura o el peso.
Los campos personalizados se pueden agregar implementando los reagent-forms.core/init-field . El método debe tomar dos parámetros, donde el primer parámetro es el componente de campo y el segundo son las opciones.
¡Por defecto, las opciones contendrán la get y el save! y update! llaves. get puntos clave a una función que acepta una ID y devuelve el valor del documento asociado con ella. ¡El save! La función acepta una identificación y un valor que estará asociado con ella. ¡La update! La función acepta una ID, una función que manejará la actualización y el valor. La función que maneja la actualización recibirá los valores antiguos y los nuevos.
Se pueden proporcionar adaptadores a los campos para crear formatos de almacenamiento personalizados para los valores de campo. Estas son un par de funciones pasadas al campo a través de las teclas :in-fn y :out-fn . :in-fn modifica el elemento almacenado para que el campo pueda usarlo mientras :out-fn modifica la salida del campo antes de que se almacene. Por ejemplo, para usar un objeto js/Date nativo como formato de almacenamiento, el capitador de date se puede inicializar así:
[ :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 %)))}]Los adaptadores se pueden pasar nulos, por lo que deben poder manejarlos.
Safari en iOS tendrá un retraso de 300 ms para :on-click , es posible establecer un evento de activación personalizado utilizando la tecla :touch-event . Vea aquí la lista de eventos disponibles en React. Por ejemplo, si quisiéramos usar :on-touch-start en lugar de :on-click para activar el evento, entonces podríamos hacer lo siguiente:
[ :input.form-control { :field :text :id :first-name :touch-event :on-touch-start }] Tenga en cuenta que también tendrá que establecer el estilo de cursor: pointer para cualquier elemento que no sea botones para que los eventos funcionen en iOS.
El tapentPlugin para React es otra opción para crear eventos receptivos, hasta que la funcionalidad esté disponible en React.
Este proyecto usa Doo para ejecutar las pruebas. Debe instalar uno de los entornos respaldados por DOO, consulte los documentos para más detalles. Para ejecutar las pruebas, por ejemplo, usando Phantom, haz:
lein doo slimer test
Copyright © 2018 Dmitri Sotnikov
Distribuido bajo la licencia pública de Eclipse, ya sea la versión 1.0 o (a su opción) cualquier versión posterior.