Search code examples
reactjsclojurescriptcodemirrorreagent

ClojureScript: how to change CodeMirror reactively with Reagent


I'm trying to embed a CodeMirror in my webpage to edit several code snippets, one at a time.

To do this I:

  • Have one Reagent atom node-defs-atom containing a map of the code snippets.
  • Have another atom node-history-atom which contains the keys of the snippets being looked at
  • Set the value of the CodeMirror to the value of the code map at the key.

Here's what doesn't work:

(defn editor [node-defs-atom node-history-atom]
  (reagent/create-class
    {:reagent-render (fn [] (do [:textarea
                     { :value (@node-defs-atom (last @node-history-atom))
                       :auto-complete "off"}]))
     :component-did-mount (editor-did-mount  node-defs-atom node-history-atom)
     }))

(defn editor-did-mount [node-defs-atom node-history-atom]
  (fn [this]
    (let [codemirror (.fromTextArea  js/CodeMirror
                                     (reagent/dom-node this)
                                     #js {:mode "clojure"
                                          :lineNumbers true})]

                            ...... )))

Changing node-history-atom with reset! doesn't do anything to the text in the CodeMirror. I'm really not sure what is going wrong.

If anyone could tell me where I should put the reference to (@node-defs-atom (last @node-history-atom)) I'd be very grateful.

Thanks in advance!


Solution

  • You can try another way to deal with the CodeMirror editor

    • Create a CM instance on an empty node

      (def cm (atom nil))
      
      (reset! cm (js/CodeMirror.
                   (.createElement js/document "div")
                   (clj->js {...})))
      
    • Then your view will be a reagent class and wrapper-id is just an id of parent

      (reagent/create-class
        {:reagent-render         (fn [] @cm [:div {:id wrapper-id}])
         :component-did-update   update-comp
         :component-did-mount    update-comp})
      
    • Create a function which appends CM to the dom node

      (defn update-comp [this]
        (when @cm
          (when-let [node (or (js/document.getElementById wrapper-id)
                              (reagent/dom-node this))]
            (.appendChild node (.getWrapperElement @cm))))