How can I use **require** in ClojureScript? - clojurescript

I ClojureScript I can do something within a ns declaration like like:
(ns demo2
(:require
[goog.ui.Textarea :as text-area]
)
)
: but :
(require '[goog.ui.Textarea :as text-area])
: doesn't work. Does anyone know what I'm doing wrong?

There is no (require) definition in ClojureScript.
As stated in the wiki page on namespaces:
You must use the :as form of :require

Related

How to implement *load-fn* for :requires in bootstrapped clojurescript

(ns scratch
(:require [cljs.js :as cjs]))
;Let's setup a simple clojurescript string eval that supports namespaces:
(def current-ns 'cljs.user)
(def compiler-state (cjs/empty-state))
(defn eval-text [text]
(println string)
(cjs/eval-str compiler-state text current-ns
{:eval cjs/js-eval
:ns current-ns
:context :expr
:def-emits-var true}
(fn [result]
(set! current-ns (:ns result))
(println result))))
(eval-text "(ns a.a)")
(eval-text "(defn add [a b] (+ a b))")
(eval-text "(add 4 4)")
;I can refer to the function from another namespace explicitly with no problem
(eval-text "(ns x.x)")
(eval-text "(a.a/add 6 6)")
;However when I do
(eval-text "(ns b.b (:require [a.a :refer [add]]))")
On the last line I get:
{:error #error {:message Could not require a.a, :data {:tag :cljs/analysis-error}, :cause #object[Error Error: No *load-fn* set]}}
So I have to create my own https://cljs.github.io/api/cljs.js/#STARload-fnSTAR
and pass it into the :load compiler option to handle this :require even though the compiler state already knows about my namespace as I can call the fully qualified function from another namespace.. Correct?
What is the best way to do that?
Should I create maps that store namespace->source-code from previously evaled code and get namespace->analysis-cache from the compiler state and pass these into the :source and :cache callbacks of my custom load function?
Is there a better / more efficient way to do this?
I believe I found the answer:
The :load option of eval-str can be set to the following function:
(defn load-dep [opts cb]
(cb {:lang :js :source ""})
And it will quite happily resolve. This isn't really apparent from the documentation that the callback can return this value when the namespace/var is already in the compiler state so I'll leave the question here.

String to Symbol in ClojureScript

Metadata of a variable such as the docstring can be read like so: Here the function map is used as an example:
(-> cljs.core/map var meta :doc)
;= "Returns a lazy sequence consisting of the result of appl....
What would I have to do to get the same result when only having the function name and its namespace as a string (as "cljs.core/map")?
Wrapping the string with the function symbol yielded an error.
Here is one way to do it:
* Clojure file *
(ns myproject.macros
(:require [clojure.string :as str]))
(defmacro doc1 [s]
(let [sym (apply symbol (str/split s #"/"))]
`(-> ~sym (var) (meta) :doc)))
* ClojureScript file *
(ns myproject.main
(:require-macros [myproject.macros :as m]))
(prn (m/doc1 "cljs.core/inc"))
=>
"Returns a number one greater than num."

Cannot use a required namespaced class

I have:
(ns test-1.core
(:require [goog.dom :as dom]
[goog.ui.Popup :as popup]
[goog.positioning.AbsolutePosition]
[rum.core :as rum]))
Now I can:
(dom/getElement "popup")
but for reasons I don't understand I cannot do :
(popup. .....)
Instead, I have to write:
(goog.ui.Popup. .....)
Why?
If you have a look at the implementation of goog.ui.Popup you can see that it is a class. This means instead of including it with :require, we need to use :import.
(ns test-1.core
(:require [goog.dom :as dom])
(:import [goog.ui Popup]))
(Popup. (dom/getElement "popup"))
Overall, use :import for Closure classes and enums, and use :require for everything else.

In ClojureScript, how to display a float with 2 decimals?

I have tried to use with-precision but it didn't work:
(.log js/console (with-precision 2 1.2345))
So I have used toFixed:
(.log js/console (.toFixed 1.2345 2))
But I feel it's not the idiomatic way of doing that.
In addition, I don't understand why with-precision doesn't work.
Please inspire me...
(ns foo.bar
(:require
[goog.string :as gstring]
[goog.string.format]))
(.log js/console (gstring/format "%.2f" 1.2345))
(ns foo.bar
(:require [cljs.pprint :as pprint]))
(pprint/cl-format nil "~,2f" 1.2345) ; => returns "1.23"
(pprint/cl-format true "~,2f" 1.2345) ; => prints "1.23", returns nil
Same code could be used in Clojure if you swap cljs.pprint with clojure.pprint.
(defn round-number
[f]
(/ (.round js/Math (* 100 f)) 100))
If you want to keep it as number type (inspired by javascript reply)

Adding a Clojurescript protocol to a Google Closure element

How can i extend a Google Closure element using Clojurescript protocols. I tried this but it doesn't seem to work:
(ns my-stuff.main
(:require
[goog.dom :as dom))
(defprotocol ds
(-set-text [this text]))
(extend-type js/HTMLDivElement
ds
(-set-text
[this text] (dom/setTextContent this text)))
(set-text (.getElementById js/document "a") "howdy")
: I must be doing something basic wrong I think as the element with ID "a" on my HTML page never gets updated.
I was working too late and didn't spot the missing - (minus sign):
(ns my-stuff.main
(:require
[goog.dom :as dom))
(defprotocol ds
(-set-text [this text]))
(extend-type js/HTMLDivElement
ds
(-set-text
[this text] (dom/setTextContent this text)))
(-set-text (.getElementById js/document "a") "howdy")