Cannot use a required namespaced class - clojurescript

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.

Related

Why does Reagent render JSON in three ways?

I am trying to render JSON data from an API call in Clojurescript/Reagent. When I use js/alert I see the json I expect: ["Sue" "Bob"]
(defn- call-api [endpoint]
(go
(let [response (<! (http/get endpoint))]
(:names (:body response)))))
;; -------------------------
;; Views
(defn home-page []
[:div (call-api "/api/names")])
This is how I'm referencing the libraries (in case there's an problem there).
(ns myapp.core
(:require [reagent.core :as reagent :refer [atom]]
[reagent.session :as session]
[cljs-http.client :as http]
[cljs.core.async :refer [<! >!]]
[secretary.core :as secretary :include-macros true]
[accountant.core :as accountant])
(:require-macros [cljs.core.async.macros :refer [go]]))
But when I log it to the console, I get a long hash that looks nothing like the API response. The browser renders "00000000000120".
Why do these results differ? (browser, alert window, console message)
How can I get what I'm seeing in the alert window to render on the page?
When you call call-api it is going to return a go block. Instead of trying to consume that go block directly in your Reagent function, you could instead update the return value in a ratom.
(def app-state (atom)) ;; ratom
(defn- call-api [endpoint]
(go
(let [response (<! (http/get endpoint))]
(reset! app-state (:names (:body response))))))
(defn home-page []
[:div #app-state])
(defn main []
(call-api))

Syntax for giving a button a particular width

How do you set a button to a particular width? This is one of the things I have tried so far:
(:require [om.next :as om :refer-macros [defui]]
[om.dom :as dom])
(defui HelloWorld
Object
(render [this]
(dom/button #js {:style {:width 300}} (get (om/props this) :title))))
Setting the title of the button works fine and is probably not relevant for this question. I've left it in because it is a typical thing to be doing, and placement of the attributes might be important.
The lein project.clj file has these dependencies:
[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.omcljs/om "1.0.0-alpha24"]
[figwheel-sidecar "0.5.0-SNAPSHOT" :scope "test"]
I think the problem is due to #js only working on the top level. #JS will work on a top level map {} or vector [], but if you have nested data as values, you need to include additional #js calls for each embedded object.
What you really need is
(:require [om.next :as om :refer-macros [defui]]
[om.dom :as dom])
(defui HelloWorld
Object
(render [this]
(dom/button #js {:style #js {:width 300}} (get (om/props this) :title))))
Have a look at this post on using #js. For readability, rather than nested #js calls, you are often better off using clj->js
I got it to work with this:
(defui HelloWorld
Object
(render [this]
(dom/button (clj->js {:style {:width 300}}) (get (om/props this) :title))))
Note the use of clj->js.

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

How can I use **require** in 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