Skip to content

Instantly share code, notes, and snippets.

@ramirez7
Last active January 2, 2016 15:59
Show Gist options
  • Select an option

  • Save ramirez7/8326931 to your computer and use it in GitHub Desktop.

Select an option

Save ramirez7/8326931 to your computer and use it in GitHub Desktop.
(ns async-tut1.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [goog.dom :as dom]
[goog.events :as events]
[cljs.core.async :refer [put! chan <!]]
[cljs.core.async :as async]))
;; ============================================================================
;; HELPERS
(defn listen [e1 type]
(let [out (chan)]
(events/listen e1 type (fn [e] (put! out e)))
out))
(defn toggle-attribute
([e a]
(toggle-attribute e a (not (true? (.hasAttribute e a)))))
([e a v]
(if (true? v)
(.setAttribute e a "")
(.removeAttribute e a))))
;; ============================================================================
;; MAIN
(let [a-button (dom/getElement "A_chk")
b-button (dom/getElement "B_chk")
c-button (dom/getElement "C_chk")
;; Direct clicks from all 3 buttons into a single input channel
checkbox-clicks (async/merge [(listen a-button "click")
(listen b-button "click")
(listen c-button "click")])]
;; push something into channel to initialize
;; there's gotta be a better way (maybe in html manually? idk)
(put! checkbox-clicks :init)
;; Whenever something gets clicked (<! checkbox-clicks), update the
;; disabled state of the buttons according to the checked state
(go (while true
(<! checkbox-clicks)
;;B button behavior
(cond
(.-checked a-button) (toggle-attribute b-button "disabled" false)
:else (toggle-attribute b-button "disabled" true))
;;C button behavior
(cond
(and (.-checked a-button) (not (.-checked b-button)))
(toggle-attribute c-button "disabled" false)
:else (toggle-attribute c-button "disabled" true)))))
;; How core.async channels work:
;; They're just queues. When an event happens, you push it into the queue,
;; and then somehwere else you pull events out of the queue and react to them.
;;
;; In this code, the listen function is where events get pushed in. This
;; function returns a channel that will have events pushed into it. For
;; instance, (listen a-button "click") will return a channel that will get
;; an event pushed into it every time the A button is clicked.
;;
;; go blocks are where events get pulled out. This is done in main.
;; The channels from listen for all three buttons are merged (using
;; async/merge) into a single channel, which will get clicks from all
;; buttons pushed into it. In the go block, (<! checkbox-clicks) means
;; this go block will pull from the clicks channel whenever something is in it.
;; In other words, it will react to every click.
;; Finally, the state of the buttons are checked in cond's, and the disabled
;; attribute is set accordingly.
;;
;; I probably didn't explain core.async channels too well as I don't perfectly
;; understand them myself. There's a really good blog about a guy who loves
;; them and works as a frontend dev at the NYT and I'm learning a lot
;; from him.
<html>
<body>
<input id="A_chk" type="checkbox">A</input>
<input id="B_chk" type="checkbox">B</input>
<input id="C_chk" type="checkbox">C</input>
<script src="out/goog/base.js" type="text/javascript"></script>
<script src="async_tut1.js" type="text/javascript"></script>
<script type="text/javascript">goog.require("async_tut1.core");</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment