Clojurians
#hoplon
<
2015-11-12
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

thedavidmeister11:11:35

after i create an element like (a :href “/foo”) is it possible for me to A. retrieve “/foo” something like (:href my-link) B. change the :href to something else?

thedavidmeister11:11:43

or alternatively, is there a way to process links on a page or something?

thedavidmeister11:11:25

the context is, trying to get an active class on links to the current page

bsima12:11:18

@thedavidmeister: you can just use JavaScript and jquery functions for accessing/changing element attributes

thedavidmeister12:11:21

i’ll give that a whirl

thedavidmeister12:11:20

(def test-link (c/a :href "foo"))

(print (. test-link attr "href”))

thedavidmeister12:11:30

am i doing that wrong @bsima ?

bsima13:11:34

(.attr test-link "href") I think. I haven't done CLJS for a while so I'm rusty on JS interop

thedavidmeister13:11:56

says that attr is not a functio

thedavidmeister13:11:20

test_link.attr is not a function

thedavidmeister13:11:58

printing test-link just gives #<Element: A>

thedavidmeister13:11:24

(print (:href test-link)) is nil

bsima13:11:02

Oh yeah. Call a jquery function like jQuery/attr I think

thedavidmeister13:11:12

hmm, not sure how to do that

thedavidmeister13:11:22

(print (.attr js/$ test-link "href”))

thedavidmeister13:11:30

is that really the best way to get at an attribute?

thedavidmeister13:11:43

seems very clunky in comparison to creating the element

thedavidmeister13:11:14

(a :href “foo”) vs. (.attr js/$ my-link “href”)

bsima13:11:26

I guess so. There's no get-attribute method in the ICustomElement protocol, but if there were then you could implement a cleaner way to get elements via keyword like you showed before https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.cljs

thedavidmeister13:11:51

is that something somebody could add to the framework?

thedavidmeister13:11:15

I might open an issue on github if it is

bsima13:11:58

The ability to do (:href my-elem) and get the attribute would be really cool, and I think it's just a matter of implementing a protocol

thedavidmeister13:11:51

any idea why addClass would not work?

bsima13:11:39

Are you using swap!?

thedavidmeister13:11:09

(defn- add-active-class!
  [a]
  (.addClass js/$ a "active”))

thedavidmeister13:11:22

(defn- get-href
  [a]
  (.attr js/$ a "href”))

thedavidmeister13:11:30

but not the adding of the class

thedavidmeister13:11:49

@bsima: soz, i’m pretty new, barely following 😛 probably can’t help actually write the protocol

thedavidmeister13:11:42

oh, because $.attr is a function

bsima13:11:45

Have long have you been doing Clojure?

thedavidmeister13:11:47

i’m just using it in a weird way

thedavidmeister13:11:14

@bsima: um, about… a week, in the evenings

bsima13:11:44

Okay, you know about immutable data?

bsima13:11:05

So add-active-class! Takes an element a returns a new element

thedavidmeister13:11:37

actually, the issue is that the attr example never “should” have worked

thedavidmeister13:11:52

it fluked because $.attr is a method, as is $(elem).attr

thedavidmeister13:11:06

so i thought i was doing the latter but actually doing the former

thedavidmeister13:11:15

there is no $.addClass so, doesn’t work

thedavidmeister13:11:32

so i’m totally doing the wrong thing, lol

thedavidmeister13:11:46

i’m happy to return a new link that has the right thing

thedavidmeister13:11:08

i can get at the :href with this approach

thedavidmeister13:11:24

i suppose i could conj on the class or something...

thedavidmeister13:11:38

this just all seems a lot harder than i was expecting >.<

thedavidmeister13:11:54

to conditionally append a class based on an existing attribute and something about the state of the system

bsima13:11:56

You could encapsulate the class in a Javelin cell

bsima13:11:08

Javelin cells are meant for modeling the state of the system after all

thedavidmeister13:11:40

yeah but then i have to put the cell on each link don’t i?

thedavidmeister13:11:12

actually, ideally i would not even be touching the a elements directly

thedavidmeister13:11:36

i’d just do something like $(a[href=“foo”]).addClass(‘active’);

thedavidmeister13:11:04

but i’m concerned that hoplon would end up being too “dynamic” for that to be a good idea

bsima13:11:11

Oh yeah. Could you use a custom element for the links?

thedavidmeister13:11:15

and i don’t know if there’s a way to “hook into” a creation

thedavidmeister13:11:42

i thought about a custom element for links, but then I’d have to be careful about consistently using my element instead of the base one everywhere

thedavidmeister13:11:59

i think that might get confusing if i’m working with someone else, easy to let a few slip through

thedavidmeister13:11:43

but actually, i end up with the same problem

thedavidmeister13:11:55

(defn- get-href
  [a]
  (.attr js/$ a "href"))

(defn- with-active-class
  [a]
  ; @TODO - Figure out how to make a have an extra class
  a)

; In this list we are able to set the class of any link that matches path-is-active.
(defn- do-active-class
  "Add an active class to anchor a if appropriate for the current path."
  [a]
  (if (url/current-path? (get-href a))
    (with-active-class a)
    (a)))

(c/defelem support []
  (c/nav
    (map do-active-class links)))

thedavidmeister13:11:27

the @TODO there needs to be done whether I decide to map a list of links or make a custom element

bsima13:11:35

Are you looking for a toggle functionality?

thedavidmeister13:11:40

it will just look like

thedavidmeister13:11:43

(defelem custom-a
  [attributes]
  ; @TODO - figure out how to add a class based on the href here.
  (a attributes))

bsima13:11:47

Btw this is a great place to look for ideas https://github.com/hoplon/demos?files=1

thedavidmeister13:11:06

an active class for any link to the current page

thedavidmeister13:11:23

so, if you’re on http://example.com/foo then any link on the page to “/foo” would have the active class

thedavidmeister13:11:05

so, you could highlight the link to the current page in a nav

thedavidmeister13:11:14

which could be header, footer, sidebar, some other thing… whatever

thedavidmeister13:11:26

like i said, ideally wouldn’t have to know in advance

thedavidmeister13:11:47

ideally would just add extra “preprocessing” to all a elements as they’re built

thedavidmeister13:11:54

@bsima: anywaaay, i think i’ve resigned myself to either mapping a list through a function that returns new links, or making a custom element

thedavidmeister13:11:19

any idea how to return a new link that has one extra class on it?

bsima13:11:55

I think javelin cells are really meant for this use case, so don't write them out too quickly

thedavidmeister13:11:05

i just don’t see how it would work

thedavidmeister13:11:18

i can’t visualise what would go where

alandipert13:11:24

@thedavidmeister: is it true to say that you want to add and remove a class to certain elements on the page depending on the current route?

thedavidmeister13:11:40

@alandipert: just add

thedavidmeister13:11:23

the page detection is pretty simple atm

thedavidmeister13:11:27

(def current-path (.. js/window -location -pathname))

(defn current-path?
  "Is the current path p?"
  [p]
  (= current-path p))

thedavidmeister13:11:13

so if the href on a link returns true for current-path?, make that link have an active class somehow

thedavidmeister13:11:34

like, class=“active” so i can style it up with CSS

alandipert13:11:16

since this involved more than one attribute... both href and class, i think this is custom element territory

alandipert13:11:32

lemme make an example one for you

alandipert14:11:05

route-cell is a thing in javelin, a cell that contains the value of the current hash fragment

alandipert14:11:19

there is a little delay because it uses a setinterval to update

thedavidmeister14:11:47

i notice that sets the class

thedavidmeister14:11:50

instead of adding it

thedavidmeister14:11:58

which would blow away any existing classes

thedavidmeister14:11:48

(defn- do-active-class
  "Add an active class to anchor a if appropriate for the current path."
  [a]
  (when (url/current-path? (get-href a))
    (.addClass (.$ js/window a) "active")))

thedavidmeister14:11:29

Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node’.

thedavidmeister14:11:45

so i’ll try your setup @alandipert and try to tweak it to see if it can work with adding instead of setting

thedavidmeister14:11:44

it’s like 1:30am here

thedavidmeister14:11:56

thanks for the help

thedavidmeister14:11:02

i’ll experiment some more tomorrow simple_smile

alandipert14:11:31

@thedavidmeister: np! yeah my version replaces the class

thedavidmeister14:11:26

as long as i can use jQuery’s addClass i think it’s OK

alandipert14:11:02

yeah, you should be able to do (.addClass (js/jQuery elem) class-name) in the do!

thedavidmeister14:11:18

is there something special about the do! that makes it not error?

alandipert14:11:40

no... the only special thing about it is it handles the attributes for all elements

alandipert14:11:10

so by adding an implementatino for :set-class we've added the :set-class attribute to all elements everywhere

thedavidmeister14:11:10

do i even need a custom element?

thedavidmeister14:11:20

or just a custom do!?

alandipert14:11:32

very nearly... but i think not since you need to know the href value to do the logic

thedavidmeister14:11:36

could i just make a :active-class that do picks up?

alandipert14:11:52

i suppose you could make a custom attribute and then inspect elem, look at its href

thedavidmeister14:11:00

yeah i could do that

alandipert14:11:19

yeah that could be sweet actually, i dunno

alandipert14:11:26

definitely worth trying

thedavidmeister14:11:27

oooh, that sounds col

thedavidmeister14:11:34

magic attributes

alandipert14:11:41

so you could make a custom attribute that takes a class name to add if the link points at the current page

alandipert14:11:56

or not to the current page, or maybe two attributes, one for each behavior 😄

thedavidmeister14:11:08

i like the idea of that if i can get it to work

thedavidmeister14:11:24

i already figured out (.attr (.$ js/window a) "href”)

thedavidmeister14:11:35

maybe I could do this in do!

thedavidmeister14:11:39

(when (current-path? (.attr (js/jQuery elem) "href"))
    (.addClass (js/jQuery elem) "active”))

thedavidmeister14:11:04

something to try tomorrow simple_smile

thedavidmeister14:11:04

if that issue ^^ got in, it would be even simpler logic

alandipert14:11:01

well, a cell must be involved in order for it to work more than once

thedavidmeister14:11:18

for me it does not have to work more than once

alandipert14:11:37

oh, interesting

thedavidmeister14:11:06

i haven’t really done any “routing"

thedavidmeister14:11:09

i just made pages

thedavidmeister14:11:21

if i ever do, i suppose i’ll revisit

thedavidmeister14:11:34

a little refactoring never killed anyone 😉

thedavidmeister14:11:40

anyway, i gotta cruise

onetom17:11:59

@thedavidmeister: even if it "doesnt have to work more than once" whats the problem with using cells for this purpose? like:

(def route (route-cell "#/default/route"))
(a :href x :class (cell= {:active (= x route)}))

onetom17:11:19

i suspect u might want some fixed attributes on the anchor tag, in which case u can do:

((a :href x :class "some non-dynamic classes") :class (cell= {:active (= x route)}))