aarkerio
aarkerio

Reputation: 2364

Calling a function from another namespace in ClojureScript

I'm a newbie with CojureScript because I got the LISP itch some months ago and then I migrated the API to Clojure and I'm loving it. Now I want to migrate the frontend too but this is my first week with CLJS.

So, I have this function:

(defn foo []
   (events/listen (gdom/getElement "icon-add") EventType.CLICK
      (fn [e] (.log js/console (str ">>> VALUE >>>>> "  e)))))

the function works great in the core.cljs file, but if I move it to users.cljs file and I call it from the core namespace with:

(ns zentaur.core
  (:require [zentaur.users :as users]

(users/foo)

the DOM element "icon-add" is never found and instead I get the error message:

Uncaught goog.asserts.AssertionError {message: "Assertion failed: Listener can not be null.", reportErrorToServer: true, 

in the browser console. If I move the function back to core.cljs, all works fine again. Then my question is: how can I move a function to another NS and be sure it keeps working?

UPDATE:

I noted that if I call the listener directly in users.cljs:

(events/listen (gdom/getElement "icon-add") EventType.CLICK
   (fn [] (.log js/console (str ">>> events/listen in users ns"))))

(I mean out of any function), all works fine, the code find the DOM element.

SECOND UPDATE

Thanks a lot for your answers but this issue looks like a "compiling time" problem. All the listeners:

(events/listen (gdom/getElement "icon-add") EventType.CLICK foo-funct)

must be loaded when CLJS runs at first time. Loading another ns is a "second time" thing and then the DOM is not reachable anymore.

Upvotes: 2

Views: 1648

Answers (3)

Chris Murphy
Chris Murphy

Reputation: 6509

The user namespace is special in that it is designed to be pre-loaded, and for development only. It is also the only time you will ever see a namespace that does not have a parent package. I say this just to warn you off using user as a namespace name - doing so will just cause confusion - whether it has a parent package or not.

Your problem seems to be that one of the arguments to events/listen is somehow returning nil. Do you have gdom as a require in zentaur.users, so: [goog.dom :as gdom]?

Upvotes: 3

Toni Vanhala
Toni Vanhala

Reputation: 1372

Google Closure library throws the assertion error because your listener function, i.e., the third parameter to listen is null.

Looking at the source code for the library, it tries to wrap the third parameter into a Listener, and the error string is produced from this failed assertion for a truthy value.

I often have similar problem, when I accidentally put extra parenthesis around the function. In effect, this leads to the function being called immediately after its declaration. This may happen without warning, even when your declared function requires one or more parameters; ClojureScript runs on JS, which does not check the arity when calling the function. Since the body of your listener is just console.log, which returns null, you would be trying to assign the null as listener.

You did note that the code example that you give is working in core.cljs. Indeed, the example does not show any obvious reason why the function is null in this case. Perhaps there was a small error in copy-pasting this function to users.cljs, e.g., extra parenthesis added?

Upvotes: 2

Alan Thompson
Alan Thompson

Reputation: 29984

In the core namespace you need to require the 2nd namespace:

(ns xyz.core
  (:require [xyz.users :as users] ))

(users/foo)  ; call the function

This assumes your code is laid out as

src
src/xyz
src/xyz/core.cljs
src/xyz/users.cljs

There are also some good ideas here on various tradeoffs in naming and references to other namespaces.

Upvotes: 3

Related Questions