Code not called from go block, but it works from REPL

Issue

I have code that updates the DOM. new-recipe! calls an API to get a new recipe string. update-recipe-state next updates this state in the screen. Finally we have a call to update-transition-buttons.

(defn- add-listener-to-recipe-button! []
  "Listens to go button, creates a new recipe and displays it"
  (create-click-event-listener! (dommy/sel1 :#button-start)
                                #(go (new-recipe!)
                                     (<! (timeout 2000))
                                     (update-recipe-state!)
                                     (<! (timeout 2000))
                                     (update-transition-buttons! "onboarding"))))

;; define your app data so that it doesn't get over-written on reload
(defonce world
  (add-listener-to-recipe-button!))

The update-transition-buttons has some delays between the steps (using the timeout code here) looks as follows:

(defn- update-transition-buttons! [recipe-name]
  "Updates the buttons with the transition names"
  (go
    ;; Split response in list of actions by splitting on the comma
    (let [response (<! (http/get (get-recipe-transitions-url recipe-name)))
          transition-names (clojure.string/split (:body response) ",")]
      (go (update-buttons! transition-names)
          (<! (timeout 2000))
          (js/console.log transition-names)
          (set-button-event-handlers! transition-names)))))

So it splits the response to a string. updates-buttons changes state on the page by adding some buttons (this is visible). Again there is a timeout, and then I want to add the event handlers to the buttons. This is where it goes wrong.

The routine to create event listeners (which also contain a console.log) look as follows:

(defn- listen-to-transition-button! [name]
  "Creates click event listener on button (button HTML ID should be name)"
  (do (js/console.log (str "Listening to " name))
    (let [name-without-spaces (clojure.string/replace name " " "")
          button (dommy/sel1 (keyword (str "#" name-without-spaces)))
          action #(do (perform-action! name)
                      (update-recipe-state!))]
      (create-click-event-listener! button action))))

(defn- set-button-event-handlers! [names]
  "Creates click event listeners on the buttons (button ID should be name)"
  (map listen-to-transition-button! names))

Again you see a console.log message that should happen for each elements that is passed. The output I get in the Firefox console is:

[FIRST SERVICE CALLED]
[NEXT SERVICE CALLED]
[DISPLAY LIST OF STEPS]: [“Step1”, “Step2”, “Step3”]

What I expect is:

[FIRST SERVICE CALLED]
[NEXT SERVICE CALLED]
[DISPLAY LIST OF STEPS]: [“Step1”, “Step2”, “Step3”]
Listening to Step1
Listening to Step2
Listening to Step3

So the event handlers (which depend on the HTML generated in the step before) are not added for some reason and the console.log message is not displayed.

When I call the same code from the REPL I do see the output, i.e.:

repl=> (set-button-event-handlers! [“Step1″,”Step2”, “Step3”])
(#object[Object [object Object]] #object[Object [object Object]] #object[Object [object Object]])

And the console output is:

Listening to Step1
Listening to Step2
Listening to Step3

Why can set-button-event-handlers! be called from the REPL, but not in the update-transition-buttons method after update-buttons?

Solution

looks like the problem is here:

(map listen-to-transition-button! names)

in set-button-event-handlers!

it creates a lazy seq, and elements won’t be realized until their usage somewhere in code (which never happens), but when you call it in repl, it is being fully realized to show all the elements in output. Try changing this line to:

(doall (map listen-to-transition-button! names))

Answered By – leetwinski

Answer Checked By – Clifford M. (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.