Une bibliothèque Clojurescript pour fournir des liaisons de données de formulaire pour le réactif, voir ici pour une démo en direct.
La bibliothèque utilise un réactif atome comme magasin de documents. Les composants sont liés au document à l'aide de l'attribut :field . Cette clé sera utilisée pour décider comment le type de composant spécifique doit être lié. Le composant doit également fournir un attribut unique :id qui est utilisé pour le corréler au document. Bien que la bibliothèque soit orientée vers l'utilisation avec Twitter Bootstrap, il est assez agnostique sur les types de composants que vous créez.
L' :id peut être un mot-clé, par exemple: {:id :foo} , ou un chemin de mot-clé {:id :foo.bar} qui mappera à {:foo {:bar "value"}} . Alternativement, vous pouvez spécifier explicitement un chemin vectoriel [:foo 0 :bar] .
Par défaut, la valeur des composants est celle du champ de document, mais tous les composants prennent en charge AN :in-fn et :out-fn Fonction Attributs. :in-fn accepte la valeur du document actuelle et renvoie ce qui doit être affiché dans le composant. :out-fn accepte la valeur du composant et renvoie ce qui doit être stocké dans le document.
Les types de champs suivants sont pris en charge hors de la boîte:
Un champ de saisie peut être de type :text , :numeric , :range , :password , :email , et :textarea . Les entrées se comportent comme des entrées HTML régulières et mettent à jour l'état du document lorsque l'événement :on-change est déclenché.
[ :input.form-control { :field :text :id :first-name }]
[ :input.form-control { :field :numeric :id :age }] Les champs d'entrée peuvent avoir un attribut facultatif :fmt qui peut fournir une chaîne de format pour la valeur:
[ :input.form-control
{ :field :numeric :fmt " %.2f " :id :bmi :disabled true }]Entrées numériques Attributs de support pour l'entrée du nombre HTML 5:
[ :input
{ :field :numeric
:id :volume
:fmt " %.2f "
:step " 0.1 "
:min 0
:max 10 }] Le champ Typeahead utilise une clé :data-source liée à une fonction qui prend l'entrée actuelle et renvoie une liste des résultats correspondants. Le contrôle utilise un élément d'entrée pour gérer l'entrée de l'utilisateur et rend la liste des choix en tant qu'élément de liste non ordonné contenant un ou plusieurs éléments d'élément de liste. Les utilisateurs peuvent spécifier les classes CSS utilisées pour rendre chacun de ces éléments à l'aide des touches: Classe d'entrée ,: Classe de liste et: classe d'élément. Les utilisateurs peuvent en outre spécifier une classe CSS pour gérer la mise en évidence de la sélection actuelle avec la touche: Classe de surbrillance. Les classes CSS de référence sont incluses dans le fichier Resources / Public / CSS / Reagent-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 " }]Le champ Typeahead prend en charge la sélection de la souris et du clavier.
Vous pouvez rendre la valeur affichée de l'entrée différente de la valeur stockée dans le document. Vous devez spécifier :out-fn , A :result-fn et éventuellement :in-fn . Le :data-source doit renvoyer un vecteur [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 }]]] Si :data-source répond avec la liste des options complète lors de la réussite du mot-clé :all , alors la touche de la flèche en bas affichera la liste.
L'attribut :selections peut être spécifiée pour passer un atome utilisé pour maintenir les sélections. Cela donne la possibilité de récupérer la liste à l'aide de Typeahead Text - si un gestionnaire de réponse Ajax définit l'atome, la liste va éclater.
S'il est fourni, la fonction :get-index garantira que l'élément sélectionné est mis en surbrillance lorsque la liste est apparue.
Un exemple complet est disponible dans le code source de la page de démonstration.
Le champ à cocher crée un élément à cocher:
[ :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 case à cocher accepte un attribut facultatif :checked . Lorsque le jeu, la case sera sélectionnée et le chemin du document indiqué par la touche :id sera défini sur 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 }]]] Le contrôle de plage utilise les touches :min et :max pour créer une entrée de plage HTML:
[ :input.form-control
{ :field :range :min 10 :max 100 :id :some-range }] Les boutons radio n'utilisent pas la touche :id car il doit être unique et est plutôt regroupé à l'aide de l'attribut :name . L'attribut :value est utilisé pour indiquer la valeur enregistrée dans le document:
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection }]
[ :input { :field :radio :value :c :name :radioselection }] Le bouton radio accepte un attribut facultatif :checked . Lorsque le jeu, la case sera sélectionnée et le chemin du document indiqué par la touche :name sera défini sur true .
[ :input { :field :radio :value :a :name :radioselection }]
[ :input { :field :radio :value :b :name :radioselection :checked true }]
[ :input { :field :radio :value :c :name :radioselection }] Le champ de fichier lie l'objet File d'un <input type="file"/> .
[ :input { :field :file :type :file }] Identique au fichier, sauf qu'il fonctionne avec <input type="file" multiple/> et lie l'ensemble de l'objet FileList .
[ :input { :field :files :type :file :multiple true }] Les champs de liste contiennent des éléments enfants dont les valeurs sont remplies dans le document lorsqu'ils sont sélectionnés. Les éléments enfants doivent chacun avoir un :key pointant vers la valeur qui sera enregistrée dans le document. La valeur de l'élément doit être un mot-clé.
Les éléments peuvent avoir une facultation :visible? mot-clé qui pointe vers une fonction de prédicat. La fonction doit accepter le document et renvoyer une valeur booléenne indiquant si le champ doit être affiché.
Le champ :list est utilisé pour créer des éléments HTML select contenant des éléments enfants option :
[ :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])]Le champ unique se comporte comme la liste, mais prend en charge différents types d'éléments et permet de désécher les champs:
[ :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 " ]]Le champ multi-sélection permet de sélectionner et de définir plusieurs valeurs dans le document:
[ :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 " ]] Les étiquettes peuvent être associées à une clé du document à l'aide de l'attribut :id et afficheront la valeur à cette touche. Les lables peuvent avoir une touche facultative :preamble et :postamble atmans avec le texte qui sera rendu respectivement avant et après la valeur respectivement. La valeur peut également être interprétée à l'aide d'une fonction de format attribuée à la touche :fmt . La touche :placeholder peut être utilisée pour fournir du texte qui sera affiché en l'absence d'une valeur:
[ :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 " )}] Les alertes sont liées à un ID d'un champ qui déclenche l'alerte et peut avoir une clé :event La clé d'événement doit indiquer une fonction qui renvoie une valeur booléenne.
Un facultatif :closeable? true/false peut être fourni pour contrôler si un bouton de fermeture doit être rendu (par défaut est vrai).
Lorsqu'un événement est fourni, le corps de l'alerte est rendu chaque fois que l'événement revient vrai:
[ :input { :field :text :id :first-name }]
[ :div.alert.alert-success { :field :alert :id :last-name :event empty?} " first name is empty! " ]Lorsqu'aucun événement n'est fourni, l'alerte est affichée chaque fois que la valeur de l'ID n'est pas vide et affiche la valeur:
( 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 date est stockée dans le document à l'aide du format suivant:
{ :year 2014 :month 11 :day 24 } Le DatePicker peut également prendre une option :auto-close? Clé pour indiquer qu'il doit être fermé lorsque le jour est cliqué. Cela par défaut est false .
Le format de date peut être défini à l'aide de la touche :date-format :
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " } Le :date-format peut également pointer vers une fonction qui renvoie la date formatée:
{ :field :datepicker
:id :date
:date-format ( fn [{ :keys [year month day]}] ( str year " / " month " / " day))} Ce qui précède est utile en conjonction avec la clé :save-fn qui vous permet de fournir une fonction personnalisée pour enregistrer la valeur. Par exemple, si vous vouliez utiliser un objet JavaScript Date, vous pouvez effectuer ce qui suit:
[ :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 }]Notez que vous devez renvoyer un nouvel objet de date dans les mises à jour pour que le composant repensait.
DatePicker prend une touche :lang facultative que vous pouvez utiliser pour définir le lieu du DatePicker. Il y a actuellement l'anglais, le russe, l'allemand, le français, l'espagnol, le portugais, le finlandais et le néerlandais construits en traductions. Pour utiliser un langage intégré Pass In :lang avec un mot-clé comme dans le tableau suivant:
| Langue | Mot-clé |
|---|---|
| Anglais | :en-US (par défaut) |
| russe | :ru-RU |
| Allemand | :de-DE |
| Français | :fr-FR |
| Espagnol | :es-ES |
| portugais | :pt-PT |
| finlandais | :fi-FI |
| Néerlandais | :nl-NL |
Exemple d'utilisation d'un paramètre de langue intégré:
{ :field :datepicker :id :date :date-format " yyyy/mm/dd " :inline true :lang :ru-RU } Vous pouvez également fournir un lieu de hasard personnalisé au DatePicker. :first-day marque le premier jour de la semaine à partir du dimanche à 0 ans. Toutes les clés doivent être spécifiées.
Exemple d'utilisation d'un paramètre local personnalisé:
{ :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 }} Le DatePicker nécessite un CSS supplémentaire pour être rendu correctement. Le CSS par défaut est fourni dans reagent-forms.css dans le chemin de la ressource. Assurez-vous simplement qu'il est inclus sur la page. Le fichier peut être lu en utilisant:
( -> " reagent-forms.css " clojure.java.io/resource slurp)L'élément de conteneur peut être utilisé pour regrouper différents éléments. Le conteneur peut être utilisé pour définir la visibilité de plusieurs éléments.
[ :div.form-group
{ :field :container
:visible? #( :show-name? %)}
[ :input { :field :text :id :first-name }]
[ :input { :field :text :id :last-name }]] Une fonction Validator peut être attachée à un composant à l'aide du mot-clé :validator . Cette fonction accepte l'état actuel du document et renvoie une collection de classes qui seront annexées à l'élément:
[ :input
{ :field :text
:id :person.name.first
:validator ( fn [doc]
( when ( -> doc :person :name :first empty?)
[ " error " ]))}] Les composants peuvent fournir un facultatif :visible? Clé dans leurs attributs qui pointe vers une fonction de décision. La fonction devrait prendre la valeur actuelle du document et produire une valeur de vérité qui sera utilisée pour décider si le composant doit être rendu, par exemple:
( def form
[ :div
[ :input { :field :text
:id :foo }]
[ :input { :field :text
:visible? ( fn [doc] ( empty? ( :foo doc)))
:id :bar }]]) La clé :set-attributes peut être utilisée dans les cas où vous devez effectuer une mise à jour arbitraire sur les attributs du composant. La clé doit pointer vers une fonction qui accepte la valeur actuelle du document et la carte des attributs du composant. La fonction doit renvoyer une carte d'attribut mise à jour:
[ :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 ))))}]]L'exemple ci-dessus désactive l'entrée du nom de famille lorsque la valeur de l'entrée du prénom est "bob".
Les composants du champ se comportent comme tous les autres composants de réactifs et peuvent être mélangés librement avec eux. Un exemple de formulaire complet peut être vu ci-dessous.
Les éléments de forme peuvent être liés à une structure imbriquée en utilisant le . comme séparateur de chemin. Par exemple, le composant suivant [:input {:field :text :id :person.first-name}] se lie au chemin suivant dans l'état Atom {: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 }])])note importante
Les modèles sont évalués avec impatience et vous devez toujours appeler les fonctions d'assistance comme dans l'exemple ci-dessus au lieu de les mettre dans un vecteur. Ceux-ci seront remplacés par des composants de réactifs lorsque les bind-fields seront appelés pour compiler le modèle.
Une fois un modèle de formulaire créé, il peut être lié à un document à l'aide de la fonction 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 " ))Le formulaire peut être initialisé avec un document peuplé, et les champs seront initialisés avec les valeurs qui y sont trouvées:
( 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 fonction bind-fields accepte des événements facultatifs. Les événements sont déclenchés chaque fois que le document est mis à jour et sera exécuté dans l'ordre où ils sont répertoriés. Chaque événement voit le document modifié par son prédécesseur.
L'événement doit prendre 3 paramètres, qui sont l' id , le path , la value et le document . L' id correspond à l' :id du champ, le path est le chemin du champ dans le document, la value représente la valeur qui a été modifiée sous la forme et le document contient l'état de la forme. L'événement peut rendre un document mis à jour ou nil , lorsque nil est retourné, l'état du document n'est pas modifié.
Ce qui suit est un exemple d'événement pour calculer la valeur de la clé :bmi lorsque le :weight et les clés :height sont peuplés:
( 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)))))] Vous pouvez fournir une carte personnalisée des fonctions d'événements pour bind-fields pour utiliser des formes de réactifs avec une bibliothèque comme re-frame . Dans ce cas, les formes de réactifs ne contiendront aucun état interne et fonctions fournies par vous seront utilisés pour obtenir, enregistrer et mettre à jour la valeur du champ. Voici un exemple:
( 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 visibilité des éléments peut être définie en fournissant l'ID dans un document qui sera traité comme une valeur de vérité, soit une fonction:
( 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 vous utilisez un refroidissement, il est recommandé d'utiliser des événements de rediffusion pour déclencher le recalcul des champs sous la forme. Par exemple, jetons un coup d'œil à un champ d'IMC calculé:
( 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 sera déclenchée lorsque l'événement :set-value est appelé, et il calculera l'IMC chaque fois que la hauteur ou le poids est mis à jour.
Des champs personnalisés peuvent être ajoutés en implémentant les reagent-forms.core/init-field . La méthode doit prendre deux paramètres, où le premier paramètre est le composant de champ et le second est les options.
Par défaut, les options contiendront le get et la save! et update! Clés. La clé get pointe vers une fonction qui accepte un ID et renvoie la valeur du document qui lui est associée. La save! La fonction accepte un ID et une valeur qui lui sera associée. La update! La fonction accepte un ID, une fonction qui gérera la mise à jour et la valeur. La fonction gérant la mise à jour recevra l'ancien et les nouvelles valeurs.
Les adaptateurs peuvent être fournis aux champs afin de créer des formats de stockage personnalisés pour les valeurs de champ. Ce sont une paire de fonctions transmises sur le terrain à travers les touches :in-fn et :out-fn . :in-fn modifie l'élément stocké afin que le champ puisse l'utiliser pendant que :out-fn modifie la sortie du champ avant d'être stocké. Par exemple, afin d'utiliser un objet js/Date natif comme format de stockage, le DatePicker peut être initialisé ainsi:
[ :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 %)))}]Les adaptateurs peuvent être passés nuls afin qu'ils doivent être capables de les gérer.
Safari sur iOS aura un délai de 300 ms pour les événements :on-click , il est possible de définir un événement de déclenchement personnalisé à l'aide de la touche :touch-event . Voir ici pour la liste des événements disponibles dans React. Par exemple, si nous voulions utiliser :on-touch-start au lieu de :on-click pour déclencher l'événement, nous pourrions faire ce qui suit:
[ :input.form-control { :field :text :id :first-name :touch-event :on-touch-start }] Notez que vous devrez également définir le style de cursor: pointer pour tous les éléments autres que les boutons afin que les événements fonctionnent sur iOS.
Le TapeventPlugin pour React est une autre option pour créer des événements réactifs, jusqu'à ce que la fonctionnalité soit disponible dans React lui-même.
Ce projet utilise Doo pour exécuter les tests. Vous devez installer l'un des environnements soutenus par DOO, reportez-vous aux documents pour plus de détails. Pour exécuter les tests, par exemple en utilisant Phantom, faites:
lein doo slimer test
Copyright © 2018 Dmitri Sotnikov
Distribué sous la licence publique Eclipse soit la version 1.0 ou (à votre option) toute version ultérieure.