Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added support for using a map to bind multiple fields to atom. fixes #2

  • Loading branch information...
commit 240f09986a44f634f4e6d74c19f058617558307a 1 parent b27d236
@mjtodd mjtodd authored
View
2  README.md
@@ -30,6 +30,8 @@ As well as binding UI elements to functions that are dependent on atoms, atoms c
For checkbox inputs, special handling is applied, so that you can bind an atom with a boolean value in exactly the same way.
+If the atom is a map, then multiple input elements can be bound to the atom. In this case, the id of the input element is used as the key to lookup the particular item in the map e.g. `<input bindatom="sample.myatom" type="text" id="mykey"` will bind the input to the item in the map with key `:mykey`. Again, this will be a two way binding, so whenever the input fires the change event, the atom will be updated with a new map.
+
### Sequences and loops
In addition to binding form input elements to atoms, you can also bind regions of html to an atom that is a sequence. This will clone the region of html for each item in the sequence. The region of html can also contain bindings. In this case, the binding functions will be called with a single parameter, which is the item from the sequence. This is best demonstrated with an example:
View
10 examples/maptest/.gitignore
@@ -0,0 +1,10 @@
+/target
+/lib
+/classes
+/checkouts
+pom.xml
+*.jar
+*.class
+.lein-deps-sum
+.lein-failures
+.lein-plugins
View
13 examples/maptest/README.md
@@ -0,0 +1,13 @@
+# binding-maptest
+
+A simple example for the cljs-binding library showing how a single atom that is a map can be used to bind to multiple input fields
+
+## Usage
+
+Run `lein cljsbuild once` to compile the ClojureScript, then simply open index.html
+
+## License
+
+Copyright © 2012 Fluent Software Solutions Ltd
+
+Distributed under the Eclipse Public License, the same as Clojure.
View
389 examples/maptest/base.css
@@ -0,0 +1,389 @@
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: none;
+ font-size: 100%;
+ vertical-align: baseline;
+ font-family: inherit;
+ color: inherit;
+ -webkit-appearance: none;
+ /*-moz-appearance: none;*/
+ -ms-appearance: none;
+ -o-appearance: none;
+ appearance: none;
+}
+
+body {
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ line-height: 1.4em;
+ background: #eeeeee;
+ color: #4d4d4d;
+ width: 550px;
+ margin: 0 auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ -o-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+}
+
+#todoapp {
+ background: #fff;
+ background: rgba(255, 255, 255, 0.9);
+ margin: 130px 0 40px 0;
+ border: 1px solid #ccc;
+ position: relative;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+ box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
+ 0 25px 50px 0 rgba(0, 0, 0, 0.15);
+}
+
+#todoapp:before {
+ content: '';
+ border-left: 1px solid #f5d6d6;
+ border-right: 1px solid #f5d6d6;
+ width: 2px;
+ position: absolute;
+ top: 0;
+ left: 40px;
+ height: 100%;
+}
+
+#todoapp h1 {
+ position: absolute;
+ top: -120px;
+ width: 100%;
+ font-size: 70px;
+ font-weight: bold;
+ text-align: center;
+ color: #b3b3b3;
+ color: rgba(255, 255, 255, 0.3);
+ text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
+ -webkit-text-rendering: optimizeLegibility;
+ -moz-text-rendering: optimizeLegibility;
+ -ms-text-rendering: optimizeLegibility;
+ -o-text-rendering: optimizeLegibility;
+ text-rendering: optimizeLegibility;
+}
+
+#header {
+ padding-top: 15px;
+ border-radius: inherit;
+}
+
+#todoapp header:before {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ height: 15px;
+ z-index: 2;
+ border-bottom: 1px solid #6c615c;
+ background: #8d7d77;
+ background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
+ background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
+ background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
+ background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
+ background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
+ background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
+ border-radius: inherit;
+}
+
+#todoapp input::-webkit-input-placeholder {
+ font-style: italic;
+}
+
+#todoapp input:-moz-placeholder {
+ font-style: italic;
+ color: #a9a9a9;
+}
+
+#new-todo,
+.edit {
+ margin: 0;
+ width: 100%;
+ font-size: 24px;
+ font-family: inherit;
+ line-height: 1.4em;
+ border: 0;
+ outline: none;
+ color: inherit;
+ padding: 6px;
+ border: 1px solid #999;
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ -o-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+}
+
+#new-todo {
+ padding: 16px 16px 16px 60px;
+ border: none;
+ background: rgba(0, 0, 0, 0.02);
+ position: relative;
+ z-index: 2;
+ box-shadow: none;
+}
+
+#main {
+ position: relative;
+ z-index: 2;
+ border-top: 1px dotted #adadad;
+}
+
+label[for='toggle-all'] {
+ display: none;
+}
+
+#toggle-all {
+ position: absolute;
+ top: -42px;
+ left: 12px;
+ text-align: center;
+ -webkit-appearance: none;
+ /*-moz-appearance: none;*/
+ -ms-appearance: none;
+ -o-appearance: none;
+ appearance: none;
+ -webkit-transform: rotate(90deg);
+ /*-moz-transform: rotate(90deg);*/
+ -ms-transform: rotate(90deg);
+ /*-o-transform: rotate(90deg);*/
+ transform: rotate(90deg);
+}
+
+#toggle-all:before {
+ content: '»';
+ font-size: 28px;
+ color: #d9d9d9;
+ padding: 0 25px 7px;
+}
+
+#toggle-all:checked:before {
+ color: #737373;
+}
+
+/* Need this ugly hack, since only
+WebKit supports styling of inputs */
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ #toggle-all {
+ top: -52px;
+ left: -11px;
+ }
+}
+
+#todo-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+#todo-list li {
+ position: relative;
+ font-size: 24px;
+ border-bottom: 1px dotted #ccc;
+}
+
+#todo-list li:last-child {
+ border-bottom: none;
+}
+
+#todo-list li.editing {
+ border-bottom: none;
+ padding: 0;
+}
+
+#todo-list li.editing .edit {
+ display: block;
+ width: 506px;
+ padding: 13px 17px 12px 17px;
+ margin: 0 0 0 43px;
+}
+
+#todo-list li.editing .view {
+ display: none;
+}
+
+#todo-list li .toggle {
+ text-align: center;
+ width: 35px;
+ -webkit-appearance: none;
+ /*-moz-appearance: none;*/
+ -ms-appearance: none;
+ -o-appearance: none;
+ appearance: none;
+}
+
+#todo-list li .toggle:after {
+ font-size: 18px;
+ content: '';
+ line-height: 40px;
+ font-size: 20px;
+ color: #d9d9d9;
+ text-shadow: 0 -1px 0 #bfbfbf;
+}
+
+#todo-list li .toggle:checked:after {
+ color: #85ada7;
+ text-shadow: 0 1px 0 #669991;
+ bottom: 1px;
+ position: relative;
+}
+
+#todo-list li label {
+ word-break: break-word;
+ margin: 20px 15px;
+ display: inline-block;
+ -webkit-transition: color 0.4s;
+ -moz-transition: color 0.4s;
+ -ms-transition: color 0.4s;
+ -o-transition: color 0.4s;
+ transition: color 0.4s;
+}
+
+#todo-list li.completed label {
+ color: #a9a9a9;
+ text-decoration: line-through;
+}
+
+#todo-list li .destroy {
+ display: none;
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ width: 40px;
+ height: 40px;
+ font-size: 22px;
+ color: #a88a8a;
+ -webkit-transition: all 0.2s;
+ -moz-transition: all 0.2s;
+ -ms-transition: all 0.2s;
+ -o-transition: all 0.2s;
+ transition: all 0.2s;
+}
+
+#todo-list li .destroy:hover {
+ text-shadow: 0 0 1px #000,
+ 0 0 10px rgba(199, 107, 107, 0.8);
+ -webkit-transform: scale(1.3);
+ -moz-transform: scale(1.3);
+ -ms-transform: scale(1.3);
+ -o-transform: scale(1.3);
+ transform: scale(1.3);
+}
+
+#todo-list li .destroy:after {
+ content: '';
+}
+
+#todo-list li:hover .destroy {
+ display: block;
+}
+
+#todo-list li .edit {
+ display: none;
+}
+
+#todo-list li.editing:last-child {
+ margin-bottom: -1px;
+}
+
+#footer {
+ color: #777;
+ padding: 0 15px;
+ position: absolute;
+ right: 0;
+ bottom: -31px;
+ left: 0;
+ z-index: 1;
+ text-align: center;
+}
+
+#footer:before {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 31px;
+ left: 0;
+ height: 100px;
+ z-index: -1;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
+ 0 6px 0 -3px rgba(255, 255, 255, 0.8),
+ 0 7px 1px -3px rgba(0, 0, 0, 0.3),
+ 0 42px 0 -6px rgba(255, 255, 255, 0.8),
+ 0 43px 2px -6px rgba(0, 0, 0, 0.2);
+}
+
+#todo-count {
+ float: left;
+ text-align: left;
+}
+
+#filters {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ right: 0;
+ left: 0;
+}
+
+#filters li {
+ display: inline;
+}
+
+#filters li a {
+ color: #83756f;
+ margin: 2px;
+ text-decoration: none;
+}
+
+#filters li a.selected {
+ font-weight: bold;
+}
+
+#clear-completed {
+ float: right;
+ line-height: 20px;
+ text-decoration: none;
+ background: rgba(0, 0, 0, 0.1);
+ font-size: 11px;
+ padding: 0 10px;
+ position: relative;
+ border-radius: 3px;
+ box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
+}
+
+#clear-completed:hover {
+ background: rgba(0, 0, 0, 0.15);
+ box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
+}
+
+#info {
+ margin: 65px auto 0;
+ color: #a6a6a6;
+ font-size: 12px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
+ text-align: center;
+}
+
+#info a {
+ color: inherit;
+}
View
23 examples/maptest/index.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <title>cljs-binding • map test</title>
+ <link rel="stylesheet" href="base.css">
+</head>
+<body>
+ <div>
+ <form>
+ <label>name</label><input type='text' id='name' bindatom='maptest.customer'><br>
+ <label>phone</label><input type='text' id='phone' bindatom='maptest.customer'>
+ </form>
+ </div>
+ <footer id="info">
+ <p>Created by <a href="http://www.fluentsoftware.co.uk/">Fluent Software</a></p>
+ </footer>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script src="maptest.js" type="text/javascript"></script>
+ <script>$(function() {cljsbinding.boot()})</script>
+</body>
+</html>
View
15 examples/maptest/project.clj
@@ -0,0 +1,15 @@
+(defproject binding-maptest "0.1.0-SNAPSHOT"
+ :description "Example demonstrating cljs-binding use of bindatom with maps"
+ :url "http://example.com/FIXME"
+ :license {:name "Eclipse Public License"
+ :url "http://www.eclipse.org/legal/epl-v10.html"}
+ :dependencies [[org.clojure/clojure "1.3.0"]
+ [fluentsoftware/cljs-binding "1.0.0-SNAPSHOT"]]
+ :plugins [[lein-cljsbuild "0.2.1"]]
+ :cljsbuild {
+ :builds [{:source-path "src-cljs"
+ :jar true
+ :compiler {:output-to "maptest.js"
+ :optimizations :whitespace
+ :pretty-print true}}]}
+)
View
5 examples/maptest/src-cljs/maptest.cljs
@@ -0,0 +1,5 @@
+(ns maptest
+ (:require [cljsbinding :as binding])
+)
+
+(def customer (atom {:name "customer name" :phone "0123 456789"}))
View
3  examples/todo/project.clj
@@ -5,8 +5,7 @@
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.3.0"]
[fluentsoftware/cljs-binding "1.0.0-SNAPSHOT"]]
- :dev-dependencies [[lein-cljsbuild "0.1.9"]]
- :plugins [[lein-cljsbuild "0.1.9"]]
+ :plugins [[lein-cljsbuild "0.2.1"]]
:cljsbuild {
:builds [{:source-path "src-cljs"
:jar true
View
3  project.clj
@@ -2,8 +2,7 @@
:description "ClojureScript binding library"
:dependencies [[org.clojure/clojure "1.3.0"]
[jayq "0.1.0-alpha1"]]
- :dev-dependencies [[lein-cljsbuild "0.1.9"]]
- :plugins [[lein-cljsbuild "0.1.9"]]
+ :plugins [[lein-cljsbuild "0.2.1"]]
:hooks [leiningen.cljsbuild]
:cljsbuild {
:builds [{:source-path "src-cljs"
View
23 src-cljs/cljsbinding.cljs
@@ -74,22 +74,37 @@
(doseq [data (.split (attr elem "bind") ";")] (bind-elem elem (.split data ":") ctx))
)
+(defn atom-val [elem]
+ (let [aval (deref (js/eval (attr elem "bindatom")))]
+ (if (map? aval)
+ (aval (keyword (attr elem "id")))
+ aval)
+ )
+)
+
+(defn reset-atom-val [elem atom val]
+ (if (map? @atom)
+ (swap! atom #(assoc % (keyword (attr elem "id")) val))
+ (reset! atom val)
+ )
+)
+
(defn bind-input-atom [elem]
- (run-bind-fn #(.call (aget elem "val") elem (deref (js/eval (attr elem "bindatom")))))
+ (run-bind-fn #(.call (aget elem "val") elem (atom-val elem)))
(.change elem
(fn []
- (reset! (js/eval (attr elem "bindatom")) (.val elem))
+ (reset-atom-val elem (js/eval (attr elem "bindatom")) (.val elem))
false)
)
)
(defn bind-checkbox-atom [elem]
- (run-bind-fn #(checked elem (deref (js/eval (attr elem "bindatom")))))
+ (run-bind-fn #(checked elem (atom-val elem)))
(.change elem
(fn []
- (reset! (js/eval (attr elem "bindatom")) (.is elem ":checked"))
+ (reset-atom-val elem (js/eval (attr elem "bindatom")) (.is elem ":checked"))
false)
)
)
Please sign in to comment.
Something went wrong with that request. Please try again.