Код не вызывается из блока go, но работает из REPL

У меня есть код, который обновляет DOM. new-recipe! вызывает API для получения новой строки рецепта. update-recipe-state затем обновляет это состояние на экране. Наконец, у нас есть вызов 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!))

update-transition-buttons имеет некоторые задержки между шагами (используя код тайм-аута здесь), выглядит следующим образом:

(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)))))

Таким образом, он разбивает ответ на строку. updates-buttons изменяет состояние на странице, добавляя несколько кнопок (это видно). Опять таймаут, а потом хочу добавить обработчики событий на кнопки. Вот где это идет не так.

Процедура создания прослушивателей событий (которые также содержат console.log) выглядит следующим образом:

(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))

Снова вы видите сообщение console.log, которое должно происходить для каждого переданного элемента. Вывод, который я получаю в консоли Firefox:

[ПЕРВАЯ СЛУЖБА ВЫЗЫВАЕТСЯ]
[СЛЕДУЮЩАЯ СЛУЖБА ВЫЗЫВАЕТСЯ]
[ОТОБРАЗИТЬ СПИСОК ШАГОВ]: ["Шаг1", "Шаг2", "Шаг3"]

Я ожидаю:

[ПЕРВАЯ СЛУЖБА ВЫЗЫВАЕТСЯ]
[СЛЕДУЮЩАЯ СЛУЖБА ВЫЗЫВАЕТСЯ]
[ОТОБРАЗИТЬ СПИСОК ШАГОВ]: ["Шаг1", "Шаг2", "Шаг3"]
Прослушивание Шага 1
Прослушивание Шаг 2
Прослушивание шага 3

Таким образом, обработчики событий (которые зависят от HTML, сгенерированного на предыдущем шаге) по какой-то причине не добавляются, и сообщение console.log не отображается.

Когда я вызываю тот же код из REPL, я вижу результат, т.е.:

repl=> (set-button-event-handlers! ["Шаг1","Шаг2", "Шаг3"])
(#object[Объект [объект Объект]] #object[Объект [объект Объект]] #object [Объект [Объект Объект]])

И вывод консоли:

Прослушивание Шага 1
Прослушивание Шага 2
Прослушивание Шага 3

Почему set-button-event-handlers! можно вызвать из REPL, но нельзя в методе update-transition-buttons после update-buttons?


person Erwin Rooijakkers    schedule 19.04.2016    source источник


Ответы (1)


похоже проблема здесь:

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

in set-button-event-handlers!

он создает ленивую последовательность, и элементы не будут реализованы до тех пор, пока они не будут использованы где-то в коде (чего никогда не происходит), но когда вы вызываете его в repl, он полностью реализован для отображения всех элементов в выводе. Попробуйте изменить эту строку на:

(doall (map listen-to-transition-button! names))
person leetwinski    schedule 19.04.2016