Fork me on GitHub
#hoplon
<
2017-02-03
>
kleewho08:02:44

I'm playing with hoplon/javelin/castra. Whenever I require [clj-http.client :as client] in my clojure file I get

java.lang.Exception: namespace 'clj-http.client' not found, compiling:(rsd/traxis.clj:1:1)
I have clj-http in dependencies in build.boot and clearly I have no idea what might be wrong

dm309:02:31

can you post your build.boot?

kleewho09:02:02

(set-env!
  :dependencies '[[adzerk/boot-cljs          "1.7.228-1"]
                  [adzerk/boot-reload        "0.5.0"]
                  [adzerk/boot-cljs-repl     "0.3.3"]
                  [cheshire                  "5.7.0"]
                  [clj-http                  "2.3.0"]
                  [compojure                 "1.5.2"]
                  [hoplon/castra             "3.0.0-alpha7"]
                  [hoplon/hoplon             "6.0.0-alpha17"]
                  [http-kit                  "2.2.0"]
                  [org.clojure/clojure       "1.8.0"]
                  [org.clojure/clojurescript "1.9.456"]
                  [org.clojure/tools.nrepl   "0.2.12" :scope "test"]
                  [org.clojure/tools.reader  "1.0.0-beta4"]
                  [pandeiro/boot-http        "0.7.6"]
                  [ring                      "1.5.0"]
                  [ring/ring-defaults        "0.2.1"]]
  :resource-paths #{"assets" "src/clj" }
  :source-paths   #{"src/cljs" "src/hl/rsd"})

(require
  '[adzerk.boot-cljs      :refer [cljs]]
  '[adzerk.boot-cljs-repl :refer [cljs-repl start-repl]]
  '[adzerk.boot-reload    :refer [reload]]
  '[hoplon.boot-hoplon    :refer [hoplon prerender]]
  '[pandeiro.boot-http    :refer [serve]])

(deftask dev
  "Build rsd for local development."
  []
  (comp
    (serve
      :port    8000
      :handler 'rsd.handler/app
      :reload  true
      :httpkit true)
    (watch)
    (speak)
    (hoplon)
    (reload)
    (cljs)))

(deftask prod
  "Build rsd for production deployment."
  []
  (comp
    (hoplon)
    (cljs :optimizations :advanced)
    (prerender)))

(deftask make-war
  "Build a war for deployment"
  []
  (comp (hoplon)
        (cljs :optimizations :advanced)
        (uber :as-jars true)
        (web :serve 'rsd.handler/app)
        (war)))

kleewho09:02:30

it's mostly from the hoplon-castra-template with some changed versions as it was not working right after generating

dm309:02:08

what if you do (require 'clj-http.client) directly in the repl?

kleewho09:02:54

boot.user=> (require 'clj-http.client)
nil

dm309:02:48

so that works

dm309:02:14

now (require 'rsd.traxis)?

kleewho09:02:34

I should write probably whole story. When I reload the page second time I don't have this error

kleewho09:02:53

boot.user=> (require 'rsd.traxis)
nil

dm309:02:10

if you start a new repl and require the namespace, do you have the error?

kleewho09:02:17

let me check

dm309:02:35

my guess is you won't

kleewho09:02:16

yes, it's working without errors

dm309:02:17

so you start the dev task, load the page and get the error?

kleewho09:02:38

but after second reload the error is gone

kleewho09:02:10

funny thing that it was working in the early morning, and I swear I did not change anything significant but still... it's not working

dm309:02:12

so this somehow tries to make a request to the endpoint, which tries to load the rsd.handler ns

kleewho09:02:06

yes, I have a call in init function

kleewho09:02:12

if that might help in any way I can show whatever file you want (with some minor changes)

dm309:02:58

sorry, I don't have the time to debug this now

kleewho09:02:20

sure, no problem, thanks for your time anyway

dm309:02:30

if the rsd.handler is loaded successfully on a clean repl startup - the issue is with however the boot-http/serve task initializes the ns

kleewho09:02:30

Clean repl. No problem with rsd.handler

boot.user=> (require 'rsd.handler)
nil

kleewho09:02:53

restarted the whole boot dev and now the error is gone ๐Ÿ˜•

kleewho14:02:24

I bet that's very simple but having something like this, how can I pass to click handler value of div r-id and value of div r-status

(for-tpl [r rpc/rs=]
        (div :class "event"
          (button :click #(remove "here_id" "here_status") "X")
          (div :class "r-id" id))
          (div :class "r-status" status)))))

dm314:02:21

what's the "value" of a div?

kleewho14:02:36

I mean, the text that I'm passing there

kleewho14:02:33

I wanted to just pass it when creating the button and divs but the size of the rpc/rs= is changing and divs are not recreated. Only new text is set on them and that's it, so after first button click there is a mismatch

dm314:02:19

where are you using the r that is bound in for-tpl?

kleewho14:02:55

I simplified the example. Here it is with r

(for-tpl [r rpc/rs=]
        (div :class "event"
          (button :click #(remove "here_id" "here_status") "X")
          (div :class "r-id" (text (:id r)))
          (div :class "r-status" (text (:status r)))))))

kleewho14:02:14

Does it matter though?

dm314:02:12

what do you want to achieve? Do you want to do something with the actual DOM elements or with the contents of r when the button is clicked?

kleewho14:02:46

I want to call remote system with appropriate values, then I'll get back new list in rpc/rs= with one less element

kleewho14:02:05

basically I'm removing the element but on remote system

dm314:02:23

so I guess you want to get the :id out of r, right?

dm314:02:33

which is (:id @r) inside the :click handler

dm314:02:24

thing that is bound inside the for-tpl is a Cell itself

dm314:02:36

the same way rpc/rs= is a Cell

kleewho14:02:39

I thought so, but then new list comes back and I have wrong value in button :click handler as html elemnts are the same

kleewho14:02:54

only the text on them is changing

dm314:02:10

the HTML elements will be the same

dm314:02:16

that's how for-tpl works

dm314:02:42

it shouldn't matter unless you care about the identity of the DOM elements

kleewho14:02:26

I end up with old id in the :click handler

dm314:02:28

you should, however, receive the up-to-date values of the r

dm314:02:24

can you post the snippet where you have actually wired everything up?

kleewho14:02:53

as soon as I'm in the state that anything works

dm314:02:18

did you verify that rps/rs= contains the result that you expect it to after the click?

dm314:02:55

I guess, if the text on the elements has changed...

kleewho14:02:01

yes, exactly ๐Ÿ™‚

dm314:02:30

then can you post the for-tpl snippet that uses r inside the :click handler and produces the wrong value?

kleewho14:02:26

Will this be enough?

(defn remove-recording [id status]
  (if (contains? #{"ongoing" "completed"} status)
    (rpc/delete-single id)
    (rpc/cancel-single id)))

(defn recordings-div []
  (div :id "outer-recordings"
    (h1 "Recordings:")
    (div :id "recordings"
      (for-tpl [recording rpc/recordings=]
        (div :id "vrm-rec" :class "event"
          (div :class "vrm-rec-title" (text (:title recording)))
          (button :click #(remove-recording (:id @recording) (:status @recording)) (if (contains? #{"ongoing" "completed"} (:status @recording)) "Delete" "Cancel"))
          (div :id (str "vrm-rec-id-" (:id @recording)) :class "vrm-rec-id" (text (:id recording)))
          (div :id (str "vrm-rec-status-" (:id @recording)) :class "vrm-rec-status" (text (:status recording))))))))

kleewho14:02:00

it's an evolutionary thing, so there might be some code duplication ๐Ÿ˜‰

dm314:02:33

ok, so you shouldn't be derefing the recording anywhere outside the :click handler

kleewho14:02:44

I should not?

dm314:02:51

that's how the initial value gets embedded into the DOM elements

dm314:02:59

no, you should be using cell=

dm314:02:18

(div :id (cell= (str "vrm-rec-id-" (:id recording))) ...)

dm314:02:38

this is how your elements will react to changes in the recording cell

dm314:02:24

text function does that for you

dm314:02:34

so you don't need cell= there

kleewho14:02:49

right, that's why the text is changing and the rest is not

kleewho14:02:40

Will that be ok so I don't have to repeat myself?

(let [id (cell= (:id recording))
                status (cell= (:status recording))]
            (div :class "vrm-rec-title" (text (:title recording)))
            (button :click #(remove-recording id status) (if (contains? #{"ongoing" "completed"} (:status @recording)) "Delete" "Cancel"))

dm314:02:47

except for the (if ...) part inside the button

dm314:02:55

that also has to go inside a cell

dm314:02:30

and you should be dereferencing inside the callback

dm314:02:41

because otherwise you'll get a Cell there instead of its value

kleewho14:02:51

(let [id (cell= (:id recording))
                status (cell= (:status recording))
                button-label (cell= (if (contains? #{"ongoing" "completed"} status) "Delete" "Cancel"))
                title (cell= (:title recording))]
            (div :class "vrm-rec-title" title)
            (button :click #(remove-recording @id @status) button-label)
            (div :class "vrm-rec-id" id)
            (div :class "vrm-rec-status" status))

kleewho14:02:28

so like this?

dm314:02:06

this should work

kleewho14:02:41

it's not but I probably can figure out that part. Thank you for your help!

dm314:02:35

you don't need contains? there with the set btw

dm314:02:43

(#{:x :y} :x) is the idiom

dm314:02:19

you also should return just one element from for-tpl

dm314:02:29

or from let for that matter

dm314:02:45

because the result of a function is whatever you return last

kleewho14:02:44

yes, that was it. Now it's working like a charm. Really appreciate your help!

dm314:02:58

np ๐Ÿ™‚

zilvinasu20:02:02

How popular is the actual usage of cljs.hl instead of cljs files ? (seems like once one switches to using cljs.hl, all the intellisense is lost )

dm321:02:53

you don't have to use .hl files

dm321:02:27

I don't think there are any benefits left