Fork me on GitHub
#re-frame
<
2017-02-26
>
nidu06:02:17

Hello. Let's say we a text editor - tabs for files on the top and file tree to the left. In app-db i have something like this

{:files {} ; stores some file meta
 :sidebar {:file-ids {}}
 :tabs {:file-ids {}}
Now when i delete a file (e.g. in handler :files/delete) i must also delete this file from sidebar and tabs. What would be a good way to do it? Explicitly send events like :sidebar/file-deleted and :tabs/file-deleted (looks not good because :files/delete must know about every place which is interested in file) or maybe i can set some kind of event which will be triggered when file is deleted?

pesterhazy13:02:13

@nidu, I think sidebars and tabs ideally should be derived from files, i.e. there should be a single place for each piece of information

nidu13:02:49

@pesterhazy Sidebar and tabs have specific order and display only open files so i'm not sure how to remove app-db

pesterhazy13:02:08

one way would be to add a :sidebar/position attribute to files

pesterhazy13:02:02

not saying this is the best way to do it, but I'd think about ways to normalize your data model

pesterhazy13:02:48

remember it's all in memory so unlike a durable db, scanning through all elements is lightning fast

nidu13:02:59

@pesterhazy interesting approach! However now i have to rebuild :sidebar/position and :tabs/position upon deletion quite the same way ๐Ÿ˜„

pesterhazy13:02:11

how so? you just sort by sidebar/position and don't care about gaps

pesterhazy13:02:26

of course adding a file is more complicated that way

pesterhazy13:02:22

I guess my point is you should avoid coordinated changes and instead use reactions/track/subscriptions

nidu13:02:54

@pesterhazy yeah, the problem in this case moves to file addition

pesterhazy13:02:46

well not if you always add to the beginning or end

nidu13:02:10

yeah, deriving as much as possible is good. However here i'd like to change state of one module when data changes and i'm not sure how to do it with reactions. Would be nice to change app-db in response to some reaction change

pesterhazy13:02:12

otherwise you can re-number the elements

nidu13:02:20

@pesterhazy unfortunately that's not the case

pesterhazy13:02:55

I'm not a re-frame expert, but I'm not sure state changes should trigger other state changes

pesterhazy13:02:14

it'd be better to have a single event that updates both sidebar and files at the same time

pesterhazy13:02:26

like an even add-file, delete-file etc.

pesterhazy13:02:41

that way you can be sure that there are never orphan files in sidebar...

nidu13:02:55

yeap, that's what i currently do but it couples all my modules

pesterhazy13:02:19

personally I wouldn't worry too much about coupling

pesterhazy13:02:15

it's better than a sort of a pinball event system

gregnwosu14:02:24

real newbie question here but im trying to handle an event and cause it to fire another event, heres my code

(re-frame/reg-event-fx
 :login-success
 (fn [cofx]
   (console.log  "login success called")
   (assoc cofx :active-page  :create-game)
   ))


(re-frame/reg-event-db
 :login
 (fn [cofx [_ data]]
   (console.log " login event handled")
   (assoc  cofx :db (assoc (:db cofx)  :name data) :dispatch [:login-success] )
   ))

gregnwosu14:02:13

login even it handled , however login success is never handled, can anyone suggest how i should go about diagnosing?

andrea.crotti14:02:24

anyone knows why it would be better to use :g rather than :div?

gregnwosu14:02:17

scratch that i think i have it

bpicolo14:02:02

Hi friends, trying to figure out the best way to structure this in re-frame: I have a page where I need to load some data, read it, and potentially redirect

bpicolo14:02:21

Doing that in an (if) clause in the render method seems sketch, though in theory would work. What might be better, though?

pesterhazy14:02:40

@bpicolo I don't understand the use case

bpicolo14:02:16

@pesterhazy Say a new user hits some page. I want to load their user details, and if they haven't filled them out yet, redirect them to the page where they fill out user details

bpicolo14:02:39

So my page is dependent on (subscribe [:user-details])

bpicolo14:02:47

where if those are empty I need to redirect

pesterhazy14:02:56

redirect as in a server side HTTP redirect?

bpicolo14:02:13

I mean, it's an SPA, so no

bpicolo14:02:21

just via secretary

bpicolo14:02:50

More-specifically https://github.com/venantius/accountant because it's a dope secretary wrapper ๐Ÿ˜‰

pesterhazy14:02:32

yeah you shouldn't trigger events in the render methods

bpicolo14:02:37

Yeah I get that.

bpicolo14:02:56

Hence the question ๐Ÿ˜‰

bpicolo14:02:51

I guess I could add a data loading callback to the HTTP GET, but that's kinda of a sketchy workaround of re-frame data flow

bpicolo14:02:27

Maybe a co-effect on the load is most appropriate?

bpicolo14:02:34

or effect rather

bpicolo14:02:11

uhhh I guess side effects aren't ordered so that doesnt work

pesterhazy14:02:50

so you have a page /private which is only accessible if the user has filled in her details?

pesterhazy14:02:59

can't you show the details screen instead /private on /private if it's not accessible?

bpicolo14:02:07

I could, but that really breaks app flow

pesterhazy14:02:19

in which way?

pesterhazy14:02:46

the other option would be to make the decision upon navigation

bpicolo14:02:46

It's a bit more to maintain to have a page that can show up potentially inside another

bpicolo14:02:52

rather than just have an actual separate page

bpicolo14:02:59

I mean, that's not possible if they load /private directly

bpicolo14:02:10

navigation isn't trustworthy

pesterhazy14:02:22

true but you can still have a check there

pesterhazy14:02:52

(if user-complete? [content] [:div "Please fill in your details first"])

bpicolo14:02:08

Yeah. Can do that, just doesn't feel optimal

bpicolo14:02:24

Might be the best choice, but it seems kind of crazy that check-data-redirect wouldn't be a supported flow right?

bpicolo14:02:28

That's insanely basic web app shit

pesterhazy14:02:48

what I've learned over the last year is that normally components shouldn't make those decisions

pesterhazy14:02:11

usually the place where you want this to happen in navigation

bpicolo14:02:12

I mean I could register an extremely specific handler function, that's not generally applicable for any other page

bpicolo14:02:16

but that doesn't feel good

pesterhazy14:02:34

but I've also run into flows that are similarly problematic

bpicolo14:02:34

[:load-details-on-empty-redirect ] ๐Ÿ˜‰

bpicolo14:02:00

That's the one problem I've hit with newfangled SPA frameworks, there's some extreme trivialities that they make super hard : (

bpicolo14:02:07

Like http error handling

bpicolo14:02:19

Totally does not fit into the global-app-db architecture

pesterhazy14:02:42

well SPAs are intrinsically harder than old school web appps

pesterhazy14:02:52

because you have to re-implement browser functionality

bpicolo14:02:58

Uhh, I'm not sure that's true

pesterhazy14:02:02

(error handling, navigation, ....)

bpicolo14:02:15

That difficulty is purely a side-effect of the one-way-data-flow with a global state atom

bpicolo14:02:41

Callback hell style stuff has problems, but error handling isn't one of them ๐Ÿ˜„

pesterhazy14:02:42

don't know about that

pesterhazy14:02:03

it seems more of a limitation of React's components and re-frame's event model

bpicolo14:02:13

Right, the latter

pesterhazy14:02:19

there's probably a nice pattern there

bpicolo14:02:21

I mean, I could make an on-before-render

bpicolo14:02:34

or whatever it's called

pesterhazy14:02:54

ok so something I usually do is to add an event that gets triggered when a screen gets focus

pesterhazy14:02:02

i.e. when the user navigates somewhere

bpicolo14:02:17

Yeah, I mean my typical pattern is similar

pesterhazy14:02:18

you could use that to trigger a nav event

bpicolo14:02:50

(defn view-function [foo] 
    (re-frame/dispatch [:dependency1])
   (fn [foo] ())

bpicolo14:02:00

that's been a good pattern for me so far

bpicolo14:02:27

Another option is a subscriber with a side-effect but that seems baaad

pesterhazy14:02:58

you could lose the ability to play back the event history

pesterhazy14:02:09

not sure how often people actually do that though

pesterhazy14:02:39

but losing that ability seems like it could defeat the purpose of re-frame

bpicolo14:02:03

@pesterhazy I think for now I'll drop it right in the same view

bpicolo14:02:08

Not thrilled about it, but works for now

bpicolo14:02:12

Thanks for discussion ๐Ÿ™‚

pesterhazy14:02:37

feels like there's a pattern there to be discovered

pesterhazy14:02:49

"landing-page + redirect"

bpicolo14:02:57

Yeah, there are a couple awkward bits

bpicolo14:02:20

one thing I'm not thrilled with is that some pages I have to wait for 3 things to load before displaying the page makes sense

bpicolo14:02:41

so I wait for 3 ratoms, but that means any ratom changing has to rerender the whole page

nidu15:02:11

@pesterhazy > it's better than a sort of a pinball event system Agree, moreover making it explicit probably makes the system more transparent

gregnwosu15:02:42

is it a bad form to call dispatch from an event-handler?

bpicolo15:02:14

there's a pattern for doing it sanely

gregnwosu15:02:08

cool , got it , read it , and its nearly working right ๐Ÿ˜„

gregnwosu15:02:12

im getting http://localhost:3449/favicon.ico 404 (Not Found)`` which folder is favicon.ico supposed to live?

pesterhazy15:02:55

that's a server side issue (also you can safely ignore it)

bpicolo15:02:46

@gregnwosu you'll need a route to /favicon.ico that serves the static asset for that

gregnwosu15:02:24

from re-frame? wont it serve things in the resource folder by default/

bpicolo15:02:58

@gregnwosu Oh no clue, I'm not using clojure on the backend

gregnwosu15:02:13

out of interest what do you use

bpicolo15:02:20

Those might have a specific subpath like /resources/blah

bpicolo15:02:42

in which case you'll want this in your <head> : <link rel="shortcut icon" href="/wherever/favicon.ico" />

bpicolo15:02:55

@gregnwosu Python. I'm just much more productive in it

bpicolo15:02:11

so it's my go-to for backend bits for sideprojects

gregnwosu15:02:43

ah thanks, and thanks for the link rel headsupโ€ฆ Im new to webdev ๐Ÿ˜Š

bpicolo15:02:43

gregnwosu bravery starting with clojure ๐Ÿ˜›

gregnwosu15:02:09

seems like the only sane way to do it ๐Ÿ˜›

bpicolo15:02:08

clojurescript is a lot of fun

bpicolo15:02:03

(re-frame especially)

bpicolo15:02:14

Om is a bit too academic for my liking

gregnwosu15:02:32

yeah i want to get good at serious webdev

gregnwosu15:02:45

spaโ€™s looks like i may ask a few dumb questions

andrea.crotti17:02:59

if I want to do some simple validation on some inputs

andrea.crotti17:02:17

the easiest way is just to use a class

andrea.crotti17:02:25

and then CSS to style differently

andrea.crotti17:02:45

or better some other way?