Fork me on GitHub
#clojurescript
<
2015-06-22
>
sooheon09:06:21

Tooling in the clojure-sphere really is getting better amazingly quickly

sveri09:06:06

uhm, with all the love for boot, can someone make it work on windows please -.-

Petrus Theron09:06:28

I want to animate an expanding or collapsing component with reagent. I have tried googling for "clojurescript reagent animation" and I haven't found anything definitive. Can anyone point me in the right direction? Not looking for a one-size fits all solution, just a hack to get this working. Can I just use CSS classes to ease height?

delaguardo09:06:31

use transition with transform

delaguardo09:06:13

transform: scaleY(0); transform-origin: top; transition: transform 4s ease;

ok09:06:38

My understanding is that animations are not that easy with react. CSSTransitionGroup should be a good starting point for google.

Petrus Theron10:06:50

Has anyone implemented an expand/collapse animation using reagent and React? I'm trying to get the CSS3 working, but dealing with height and max-height is tricky.

Petrus Theron11:06:57

Found this cookbook recipe, but it pegs the height at 2em: https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/ReactCSSTransitionGroup How to deal with dynamic content height?

joelkuiper14:06:25

@petrus: afaik most collapse animations rely on some arbitrary max-height trick … that should be doable with something like Reagent+CSSTransitionGroup, see for example https://gist.github.com/joelkuiper/5f8de31f2a3bf69fdeab

joelkuiper14:06:10

if you wanna do it without the max-height I guess you’d have to be slightly more clever about the animation and do it fully in ClojureScript/JS, without the CSS.

joelkuiper14:06:39

like getting the height of the element off of the DOM and pushing it through an easing function, such as jQuery easing http://easings.net/

coyotespike14:06:47

Has anyone had to explicitly include a CSRF token with POST requests to a Clojure backend? ring-defaults includes ring-anti-forgery, which seems to require a token. I get "Invalid anti-forgery token" when I try a POST request.

edbond14:06:15

I think that you need to add (anti-forgery-field) call to your form.

edbond14:06:32

This will generate hidden field, you can check it via view-source in browser.

coyotespike15:06:04

@edbond: btw, I've read your previous post about this on Stackoverflow - thanks for going above and beyond by creating a repo just to answer the question! I did read Usage, but I can't figure out where to put the (anti-forgery-field) call in my handler.clj (and of course can't use it in ClojureScript).

edbond15:06:55

@coyotespike: this function returns string that you need to add to form on html page

edbond15:06:22

@coyotespike: how do you render templates?

coyotespike15:06:24

@edbond: hmm. I'm using Reagent, so I suppose that does my rendering.

coyotespike15:06:55

I understand that my ClojureScript should get the anti-forgery token, and include it in the header of any request. I'm just unclear on how to do that, though I've pushed my google-fu to the max.

sveri15:06:07

@coyotespike: I am using: https://github.com/JulianBirch/cljs-ajax and using the low level ajax request I can do things like this: https://github.com/sveri/siwf/blob/master/src/cljs/de/sveri/siwf/helper.cljs#L41 which works for me. If you don't use cljs-ajax I guess you can look at the source and find out how the library does it

andrewmcveigh15:06:38

@coyotespike: You need to get the value of #’ring.middleware.anti-forgery/*anti-forgery-token* to your frontend. You then need to POST/PUT that value back via js/cljs as the param __anti-forgery-token

yedi15:06:55

is there a way i can access the state of a subcomponent from inside another om component

Petrus Theron15:06:18

you can pass in a callback to the subcomponent, or a shared atom

coyotespike15:06:40

@sveri: (ajax/POST) gives me a '403 Forbidden'. I liked your example but haven't been able to adapt it yet.

coyotespike16:06:46

@andrewmcveigh: I have

(defroutes routes   (GET "/token" [] *anti-forgery-token*))
in handler.clj, and
(defn save-stuff []
  (let [token (ajax/GET "/token")]
    (ajax/POST "/submit" {:__anti-forgery-token token})))

coyotespike16:06:57

on the ClojureScript side. Am I getting closer?

edbond16:06:49

@coyotespike: You need to get csrf token from server. There are several ways, you can add it as meta tag inside head tag and read it in clojurescript, or do GET request to server as in my example.

yedi16:06:38

@petrus: i decided to have my subcomponent share state with the parent by using the :state argument in om/build

yedi16:06:54

i didn't know i could use it like that but it solves my issue perfectly

edbond16:06:56

@coyotespike: yes, you get the idea. I would GET token only once and use it inside reagent forms

rauh16:06:05

I don't think you should request a CSRF token over an AJAX request. That makes the entire CSRF token useless

edbond16:06:07

@coyotespike: Rails include csrf token in head tag, I'm reading it in clojurescript as

;; <meta content="authenticity_token" name="csrf-param" />
;; <meta content="ica0hvG//Tt24UAAAn3cq0n2ixSzcYDwESXrgqvabr8=" name="csrf-token" />
;; "X-CSRF-Token:rs/t8QgCC+Q3B8gSCKSGZb0G3ek5HK1ZJloRRd7Ltnw="

(def csrf-token (dommy/attr (sel1 "meta[name='csrf-token']")
                            "content"))

edbond16:06:25

@coyotespike: and then just add it to POST/PUT requests

(http/put
                     url
                     {:form-params
                      {:name name
                       "value[]" (map :text msgs)}
                      :headers {"X-CSRF-Token"
                                csrf-token}})

edbond16:06:45

@coyotespike: in Reagent you can just add it as hidden field to form:

[:input {:type "hidden" :name "__anti-forgery-token" :value csrf-token}]
and submit forms

edbond16:06:50

or add to POST :params if you collect values manually (most likely)

coyotespike16:06:26

@edbond: For the GET approach, my handler.clj now looks like

(defroutes routes
  (POST "/submit" [] home-page)
  (GET "/token" [] (generate-string {:csrf-token
                                *anti-forgery-token*})))

coyotespike16:06:01

And my POST as before:

(defn save-stuff []
  (let [token (ajax/GET "/token")]
    (ajax/POST "/submit" {:__anti-forgery-token token})))

coyotespike16:06:46

This gives me TypeError: el is null, so maybe it worked but I failed to actually pass any data along (?)

coyotespike16:06:16

@rauh: would you suggest reading the csrf token from the head tag instead?

rauh16:06:38

@coyotespike: That's fine. What matters is that your token is somewhere in the response of the HTML page that your user will generate. If you want easy and straight forward: Just generate a global JS variable. That's what most people do

dnolen17:06:57

bootstrapped ClojureScript can now finally compile functions and function invocations simple_smile macros handling is more or less sorted out

jballanc17:06:25

@dnolen: so, any chance of getting a v0.1.0 release once bootstrapping is done? 😉

coyotespike17:06:25

@rauh: after a bit of research, I see what you mean about the global JS variable. What's the best way to do this in ClojureScript? Luminus seems to do something similar: http://www.luminusweb.net/docs/clojurescript.md#ajax

dnolen18:06:45

@jballanc: unlikely, been playing around with idea that ClojureScript just adopts Clojure’s version numbers as this really has been the case for a long time that ClojureScript is pinned to Clojure.

dnolen18:06:53

so more like Transit

dnolen18:06:01

1.7.COMMITN

chris18:06:36

that’s a good idea

chris18:06:47

they’re tied together anyways

sveri18:06:27

@coyotespike: Sorry, I missed the half part, not sure if you got it working inbetween, to get the AF token to the frontend I include it in the data map using selmer: https://github.com/sveri/siwf/blob/master/src/clj/de/sveri/siwf/layout.clj, which is then rendered by selmer in the template itself: https://github.com/sveri/siwf/blob/master/resources/templates/files.html. Then you can follow the other links I posted before. So, it's like the others said, somehow render it in the html page for the frontend, then grab it and add it to your ajax request.

jballanc19:06:04

@dnolen: as much as I generally oppose the idea, I wonder if there’s a need to separate the “library” version from the runtime version

dnolen19:06:26

@jballanc: I don’t know what you mean

jballanc19:06:34

i.e. even after ClojureScript reaches Clojure 1.7.0 parity, there might be need to release updates independent of Clojure

jballanc19:06:52

so then does that become ClojureScript 1.7.1?…or something else?

dnolen19:06:16

nothing about the release approach is going to change, the cycles will just get longer

dnolen19:06:56

the only that would change is the versioning mechanism, and the appearance of ClojureScript releases when Clojure has releases

dnolen19:06:37

the ClojureScript release cycle will likely slow down to one every couple of months now that the REPL stuff is behind us

jballanc19:06:42

ah, ok…seems reasonable enough

jballanc19:06:31

(FWIW, I know Ruby tried the “library version” vs “runtime version” thing with the 1.9 series, where Ruby 1.9.3 was still using the 1.9.0 library version, and it confused the hell out of everyone)

arohner20:06:09

Using Om, I’m getting a "Each child in an array should have a unique "key" prop.” I’m aware of (om/build-all .. {:key :foo}), and I thought I was using it everywhere. What’s the best way to find out which code is causing that?

edbond20:06:21

@arohner: look for for and map in code

edbond20:06:49

maybe not your code, some lib?

arohner20:06:52

edbond: yeah, doing that, and a lot of comment bisecting 😕

arohner20:06:05

I was hoping for something that would maybe point at the offending dom element

dnolen20:06:46

@arohner: set a breakpoint in React and walk back up the stack

arohner21:06:05

I’ve gotten rid of all my react warnings, and I’m still seeing weird behavior. I have an html table, with rows. The rows are rendered using om/build-all. When I (om/set-state! owner :rows [..]) with one less row than it used to have (delete), the table doesn’t re-render, as demonstrated with println. The deleted row does re-render, but no other row does

noprompt23:06:35

exciting stuff!

noprompt23:06:58

@arohner: are you using sablono?

arohner23:06:32

I figured out my re-render bug

arohner23:06:52

it was a goloop race condition, with a poorly-placed when

noprompt23:06:45

@arohner: ah, ok. sometimes those messages come up with code that must be handled by sablono.interpreter/interpret. encountered a situation like that today.

arohner23:06:28

@noprompt: yeah, that :unique keys thing I’m pretty sure is a sablono thing

arohner23:06:53

@noprompt: how do you use interpret/interpret? and why?

noprompt23:06:24

@arohner: it can be tedious but use html inside areas like if, let, when, etc. those are places where the sablono compiler cannot intelligently make a decision about what to do and must defer to the intepreter at runtime.

noprompt23:06:29

@arohner: from a clojure repl have a look at what this produces

noprompt23:06:33

(macroexpand-1
 '(html
    [:div
     [:p "I get compiled"]
     (if 42
       [:p "I get interpreted"])]))

arohner23:06:30

(js/React.createElement "div" nil (js/React.createElement "p" nil "I get compiled") (if 42 (js/React.createElement "p" nil "I get interpreted")))

arohner23:06:40

so how do you use interpret to work around?

noprompt23:06:54

ah interesting. i think that was a bad example.

noprompt23:06:13

or perhaps it's changed. well, nevermind what i said. i'm apparently an idiot.

noprompt23:06:46

ah sorry actually i'm not an idiot totally. the example was bad.

noprompt23:06:25

(macroexpand-1
 '(html
    [:div
     [:p "I get compiled"]
     (let [p [:p "I get interpreted"]]
       p)]))

;; =>

(js/React.createElement "div" nil
    (js/React.createElement "p" nil "I get compiled")
    (let* [p [:p "I get interpreted"]]
          (sablono.interpreter/interpret p)))

noprompt23:06:20

if you look at the compile-element multi-method you'll see (compile-seq content) being called the result of which is ultimately an array. i'm guessing that can cause problems and result in the complaints about keys.