1

I'm attempting to use macros to generate a series of similar Om components (e.g. a modal element which contains common boilerplate and a dynamic "body").

I've got the solution below mostly working. The one exception is accessing the appropriate owner in the form's on-submit event handler.

;; macros.clj
(defmacro build-modal
  ([disp-name body]
  `(fn [_# owner#]
    (reify
      om.core/IRender
      (~'render [_#]
                (dom/div {:class "login-view-modal"}
                         (dom/div {:class "login-view-modal-backsplash"})
                         (dom/div {:class "login-view-modal-content"}
                                  ~@body))))) nil))

;; ui.cljs
(defn login-view-modal []
  (bs-macros/build-modal 
    "login-modal" 
    '(dom/form {:on-submit (fn [event] 
                            (.preventDefault event)
                            (let [username (get-value owner "username")
                                  password (get-value owner "password")
                                  data {:email_address username
                                        :password password}]
                              (handle-login-view-modal-form-submit data)))}
                            ;; elided for brevity
                            (dom/div 
                              (dom/button "LOG IN")))))

(defcomponent home-page-view [app owner]
              (init-state [_] {:text ""})
              (render-state [this state]
                              ;; elided for brevity 
                              (dom/div (login-view-modal))))

The modal is rendered as expected, however when submitting the form I'm presented with the error: Uncaught TypeError: Cannot read property 'getDOMNode' of undefined, which seems to be because owner is not in scope. (Note, this element and its event handler functions as expected when constructed in full - i.e. without using a macro.)

How do I make the appropriate owner available to the body of the macro?

pdoherty926
  • 9,895
  • 4
  • 37
  • 68

1 Answers1

4

You need variable capture for this to work. Instead of gen-syming via owner# which will generate a unique symbol, just inline ~'owner wherever you want to refer to it.

dnolen
  • 18,496
  • 4
  • 62
  • 71
  • Thanks for the prompt response, @dnolen! Unfortunately, I'm still missing something: changing `owner` to `~'owner` results in `Uncaught TypeError: Cannot read property 'call' of undefined`. – pdoherty926 Jun 03 '15 at 04:00