Fork me on GitHub
#om
<
2016-03-14
>
cjmurphy01:03:21

With Om Next it is the state that determines the UI, and the state is changed by mutations that are effected from clicks etc. It would seem sensible for the click to be listened to but not at the same time for the appearance of the UI to change. Is it possible to do this? A case where this simple approach would help is where there is an upper limit on the number of checkboxes that can be clicked. When the user has gone over the limit clicking should be ineffective. Just an example. It would be nice to know whether there is a solution for the general case.

cjmurphy01:03:21

click -> mutation -> state -> UI

cjmurphy01:03:36

rather than:

cjmurphy01:03:54

click/UI -> mutation -> state -> UI

matthavener02:03:54

cjmurphy: you could just store the number of clicked boxes in a path that's not rendered and then determine if you need to update the rendered state based on that

matthavener02:03:04

I'm not sure if om.next optimizes that avoidance of re-render for nested data though

cjmurphy03:03:24

Thanks Matt - sounds tricky thou! I have an actual solution to my specific problem, and that is to not allow a click (b/c component is disabled) in the first place when the max has been reached. This stays 'inside' Om (applies to the other frameworks too). My question is more of a Javascript problem. I wonder if it is even possible for UI changes to only be programmatic? It would be so easy if for example components were designed so that when you returned false from an event the component's UI did not change.

tawus03:03:01

@cjmurphy: What would be the role of local state in such a model ?

matthavener03:03:10

sounds incredibly hard to debug 馃槃

cjmurphy03:03:16

I think you can always ask a component itself what its state is, so not need to keep that state elsewhere. I don't want to use local state. In this case it is important for other parts of the app to know what has been 'turned on'.

matthavener03:03:27

you could always keep two state graphs -> the rendered, and the 'real'

matthavener03:03:48

and then sync real to rendered when the relevant component returned 'true'

matthavener03:03:07

it just gets tricky if you have N components viewing a single state tree

cjmurphy03:03:23

I'm aiming for simplicity. It is the components that are 'at fault'.

tomjack05:03:46

@cjmurphy: are you looking for preventDefault? not sure I understand

tawus05:03:41

How to write a query that says every field and a link [* [:link _]] ?

cjmurphy05:03:07

@tomjack: If the user clicks I don't want the tick mark to appear in the checkbox. I want Om-Next to effectively be putting that tick mark in. And I'm thinking that that's what everyone else would want too, for all components - as a general thing. I don't come from a js background so need to ask about things that might be quite obvious - like preventDefault. I'll look it up...

cjmurphy05:03:25

Thanks @tomjack - preventDefault seems like the right thing. I want absolutely nothing to happen - "I got the click - I'll (Om Next) will deal with the rest". I'll try it out a bit later...

tomjack05:03:33

I think maybe you could get what you want by :onChange (fn [e] (.preventDefault e))

tomjack05:03:57

onClick will not be enough for the people who check boxes with their keyboard

cjmurphy05:03:08

oh - I was using onClick for the checkbox, I'll try onChange then...

tomjack05:03:43

oh, I'm wrong, it seems

tomjack05:03:15

(I see my onClick hander being called when hitting the space bar on a checkbox..)

cjmurphy05:03:15

I like onClick being called when spacebar or mouse clicked on it - that's good - and that's enough too!

cjmurphy06:03:28

onClick seems like the event that is separated from the current state of the component, which is what I would like to use. There should only be one place where state is kept. If it happens to be kept in components it is best always ignored - which onClick does and onChange doesn't. So it is kind of good that keyboard events are caught by onClick as well. Of course maybe I'll then be relying on on a bug - a click is not a tap. If there's an onClick there should be an onTap.

tomjack06:03:17

well, wait, yeah, how about literally just :onChange (fn [e] (.preventDefault e)), but do what you want in other handlers?

cjmurphy06:03:53

It fully (recursively) denormalizes and you don't want it to. But that's what db->tree does. Apart from that I know nothing about union queries 馃槢

tomjack06:03:19

I am doing tree->db

cjmurphy06:03:31

@tomjack: I need to do the mutate as well. I can :onChange (fn [e] (.preventDefault e) (change-om-next-state)) I would think. Can't try it right now.

cjmurphy06:03:32

And you even have an ident on the comment.

tomjack06:03:26

looks like I'm probably giving you bad information

tomjack06:03:28

in fact you don't need to do anything at all, it seems?

tomjack06:03:42

(dom/input #js {:type "checkbox" :checked true})

tomjack06:03:51

this checkbox already cannot be unchecked by the user?

cjmurphy06:03:17

I'm already doing that. When checked false the user can still change it to true.

cjmurphy06:03:07

(dom/input #js {:type    "checkbox"
                               :checked (when selected? " ")
                               :onClick (fn [] (pick-fn) false)})

tomjack06:03:22

use :checked true or :checked false

tomjack06:03:45

:checked nil means it's an 'uncontrolled component', apparently

cjmurphy06:03:49

Right yes I was just using a space

cjmurphy06:03:14

Just copied from Semantic UI examples.

cjmurphy06:03:11

Thanks - will try later - in middle refactoring. thanks..

cjmurphy06:03:56

Could the fact that the post doesn't have an ident cause the problem? I guess you thought of that..

tomjack06:03:11

I don't really understand that yet, but Post doesn't have Ident in the unions tutorial either

tomjack06:03:16

the Ident is on DashboardItem

tomjack06:03:23

(which makes more sense in the original tutorial..)

tomjack06:03:16

the composite's children in the init state in the source are recursively normalized correctly. must have screwed up my dashboard example

tomjack06:03:02

actually, they are normalized with the ... in the Composite query, but not with say [:id]. not sure if that's a bug?

cjmurphy07:03:57

@tomjack: changing :checked (when selected? " ") away from what it was didn't help - b/c the checking done by the css anyway. However what did work perfectly is (.preventDefault e) as the first thing the event does. I'm going to use this on every single Om Next event I write!

urbanslug09:03:05

What鈥檚 the difference between shared-state and app-state in Om?

urbanslug09:03:27

The app-state is shared, am I wrong?

urbanslug12:03:56

Why do om components take two args data and owner all the time why? I can鈥檛 find this info in the docs.

urbanslug12:03:03

I鈥檓 using Om now

tomjack12:03:39

cj murphy: I really think this is exactly what you want: https://facebook.github.io/react/docs/forms.html#controlled-components

tomjack12:03:44

there is no need for preventDefault

tomjack12:03:45

the second checkbox cannot be checked or unchecked unless the first is checked

tomjack12:03:00

and the first can only be checked because of the update-state!

cjmurphy12:03:19

I found that there is no upper limit on the number of check boxes that can be checked using this code:

(dom/div #js {:className (str "ui" (if selected? " checked " " ") "checkbox")}
           (dom/input #js {:type    "checkbox"
                           :checked selected?
                           :onClick (fn [e] #_(.preventDefault e) (pick-fn))})
           (dom/label nil ""))

cjmurphy13:03:30

Notice preventDefault commented out. Yet this one works:

(dom/div #js {:className (str "ui" (if selected? " checked " " ") "checkbox")}
               (dom/input #js {:type    "checkbox"
                               :checked selected?
                               :onClick (fn [e] (.preventDefault e) (pick-fn))})
               (dom/label nil ""))

cjmurphy13:03:16

I was always using 'controlled components' (first example), but it was not working.

tomjack13:03:50

can selected? be nil? i.e. does (boolean selected?) behave the same?

cjmurphy13:03:51

I just made it nil and could not select any (as expected) because nil is false.

tomjack13:03:33

I mean without the unnecessary (?) preventDefault 馃槢

tomjack13:03:53

if selected? is nil, the component will not be controlled

cjmurphy13:03:40

So comment out prevent default and make it nil - I'll try that.

tomjack13:03:54

comment out preventDefault, and use (boolean selected?)

tomjack13:03:09

if selected? is never nil currently, then I'm wrong

tomjack13:03:34

(well, if it's already either true or false exactly)

cjmurphy13:03:50

With that I can select as many as I like - no upper bound.

cjmurphy13:03:27

oh - boolean is a function - was not sure what that was

cjmurphy13:03:56

You are correct simple_smile

cjmurphy13:03:36

With boolean function I don't need preventDefault

cjmurphy13:03:32

Thanks for your effort 馃槅馃槃

tomjack13:03:40

sure, sorry to have misled you to begin with simple_smile

tomjack14:03:03

d'oh, my union example is busted, need to make :post/comments and :comments the same https://clojurians.slack.com/files/tomjack/F0SFT7XPZ/dashboard_dashboard_cljs.clj

tomjack14:03:01

works fine after that. and even adding likes nested in comments, also works. so it's a bug in my code simple_smile

jannis14:03:10

Do folks here use tree->db a lot to extract information from deeply nested data in mutations, do you tend to resolve links manually or do you extract the info in the components and pass down everything the mutation needs down as parameters?

jannis14:03:51

I am a little undecided. I'm working with deeply nested/linked data a lot but tree->db seems such an expensive operation that wouldn't want to use it everywhere. My components on the other hand already have all links resolved into actual data via query joins but then I would like to avoid cluttering them with application logic.

anmonteiro14:03:11

@dnolen: React 15.0.0-rc.1 is up on CLJSJS, should we consider upgrading or wait for the actual 15 release?

tomjack15:03:58

I see.. in the dashboard union example, it is important that the DashboardItem ident matches the keys in the union map. This surprises me -- I was building a union where the different kinds of things all share a unique id space, giving them all matching idents, and had assumed the keys in the union map only mattered in my parser functions.

tomjack15:03:24

I was wondering how this could work; I guess it cannot. So you really must put 'union entities' into separate tables?

tomjack16:03:49

I guess I was imagining 'non-deterministic unions' where choosing the union entry is left up to parser functions, and the union'd parts of the data would always be normalized with respect to all the different union queries

tomjack16:03:49

something like: normalization takes the values in the union expr map, catvec's them, applies merge-joins, and uses that as the query to normalize

dnolen17:03:59

@anmonteiro: I would rather wait - but also would like to hear if there鈥檚 any breakage

dnolen17:03:12

@anmonteiro: thanks for rebasing the PR will take a look later today

anmonteiro17:03:15

@dnolen: OK I'll try it out locally when I have time and let you know

anmonteiro17:03:38

@dnolen: I have 2 or 3 things I'd like to run by you if you have 2 minutes

dnolen17:03:02

@anmonteiro: will have to be a little later in the day for me

anmonteiro17:03:34

@dnolen: I'll just write the questions and you answer whenever you can

anmonteiro17:03:37

1. would you be open to a PR making om.next.protocols CLJC ?

anmonteiro17:03:20

2. can I work on #398 (normalization available server-side)? I was thinking about a om.next.impl.db namespace that both om.next and om.next.server would require

anmonteiro17:03:08

(this would be quite easy to do once the PR with the helpers in om.util is merged)

folcon18:03:46

Anyone have a few minutes to explain what No queries exist for component path (om-frontend.quest/RootView om-frontend.quest/Card om-frontend.quest/OptionElement) means? I get this whenever I attempt to run a mutation. I鈥檓 structuring an small app in devcards which is like a choose your own adventure, where the top level of the app state has :cards and :current-card keys. :cards is a list of items containing an identifier, text and choices. A :current-card is a card identifier. I鈥檓 rendering the :current-card correctly with buttons for the options, but when I try to select the option, triggering a transact to change the :current-card, I get the message above. Any ideas what I鈥檓 doing wrong?

anmonteiro18:03:26

@folcon: if you share your queries for those 3 mentioned components I'm happy to take a look

anmonteiro18:03:38

I don't need the whole defui stuff, just the IQuery implementation

folcon18:03:28

;OptionElement
static om/IQuery
  (query [this]
    '[:current-card])

;Card
  static om/IQuery
  (query [this]
    '[:name :header :description :options])

;RootView
static om/IQuery
  (query [this]
    (let [subquery (om/get-query Card)]
     `[{:cards ~subquery} {:current-card [:current-card]}]))
please tell me if you need more info, more than happy to also just put in the entire source simple_smile...

anmonteiro18:03:35

@folcon: your problem is right there

anmonteiro18:03:58

queries must compose to the root with get-query

anmonteiro18:03:11

there's no way that Om knows the path from the root until OptionElement

folcon18:03:07

as in RootView should also have a get-query call to OptionElement?

anmonteiro18:03:59

I'm not sure about the structure of your UI, but if OptionElement is a child of Card, then the get-query OptionElement should be in the Card component

folcon18:03:58

ok, so Card contains an OptionView element, which contains a OptionElement

folcon18:03:16

does it matter that it鈥檚 skipped as OptionView contains no query

anmonteiro18:03:34

no problem there

folcon18:03:40

hmm, I鈥檓 now getting an invalid join. I think I should normalise the option elements by some identifier in the same way I鈥檓 doing cards. That could be a problem as there are supposed to be duplicate option elements

folcon18:03:44

is there no way to manage the option elements other than by giving them an unique identifier?

folcon18:03:26

hmm, ok the invalid join is gone, but I鈥檓 now back to the no queries exist problem鈥 Part of the issue may be that I鈥檓 using a mixture of flat and list data, simplified:

(def init-data
  {:current-card :start
   :cards [{:name :start
            ...
            :options [{:goto :stay-at-home :text 鈥淪tay"}]}
           {:name :stay-at-home
           ...
            :options [{:goto :nearest-village :text 鈥淕o to next village"}
                      {:goto :stop}]}
           {:name :nearest-village
           ...
            :options [{:goto :stay-at-home :text 鈥淩eturn"}]}
           {:name :stop}]})
So current-card acts as a selector for the :cards.

anmonteiro18:03:34

@folcon: you can always use idents

anmonteiro18:03:40

instead of keyword placeholders

folcon18:03:06

but for idents to work, I need to have a defined part of my data that I know is unique right? But the options above may not have unique parts (the goto attribute + the text maybe unique). Would I need to manage it myself?

folcon18:03:22

ok, thanks I鈥檒l try and work out how to manage that simple_smile...

adamfrey18:03:27

why does om.next recalculate props after a call to set-state!, which just touches component local state? The app state shouldn鈥檛 have changed, so why parse again? Is there something I鈥檓 missing?

iwankaramazow19:03:42

@anmonteiro I upgraded Om.next to React 15 in my local copy, seems to work without any problems for the moment...

anmonteiro19:03:42

@iwankaramazow: cool! thanks for the feedback

anmonteiro19:03:05

I wanna try a few things out myself too

anmonteiro19:03:28

namely the absence of data-reactids

anmonteiro19:03:50

and several text nodes as the children of a component which are not mapped to <span>s anymore

iwankaramazow19:03:24

the rendered html looks pretty clean without those data-reactid

anmonteiro19:03:08

also curious whether renderToString still has a data-reactchecksum

anmonteiro19:03:10

my guess is yes

iwankaramazow19:03:35

I honestly have no idea how they would do it without one

anmonteiro19:03:45

could probably be done, just very slow

iwankaramazow19:03:16

Yea performance is still the bottleneck

bostonou20:03:38

i鈥檓 trying to perform a remote mutation along with a query to read after the mutation has run. is it possible for the query to use the mutation鈥檚 result as a parameter?

bostonou20:03:26

with something like (om/transact! this 鈥榌(document/update) :document/text], I鈥檇 like the :document/text query to use the (document/update)鈥檚 value

dnolen21:03:29

@bostonou: you could maybe implement something yourself to make that work - but there鈥檚 nothing about the query syntax that would signal something like that

bostonou21:03:20

@dnolen does my question make sense as something that should be done? my struggle so far with om/next has mainly been with questions like this, e.g. I can implement something myself, but i wonder if i鈥檓 missing some design goal/approach

dnolen21:03:49

@bostonou: I could see why you might want to do that yes

bostonou21:03:57

cool. fyi, i鈥檓 checking out om/next for potentially moving to it. some really good stuff so far simple_smile

whythat21:03:54

Hi everyone! I finally moved from Om to Om Next and while setting things up I keep getting message 'TypeError: ReactDOM is undefined'. Is that some known problem or is it all my fault?

bostonou21:03:26

@whythat: you may be seeing an old version of react

anmonteiro21:03:38

@whythat: if you're using sablono you might need to also require om.dom

whythat21:03:25

@anmonteiro: I do require it, and still nothing

anmonteiro21:03:56

@whythat: what version of Om are you using?

whythat21:03:03

So far I've tried 1.0.0-alpha22 (as in GitHub guide), and also -alpha30 and -alpha31

anmonteiro21:03:53

@whythat: I would check lein deps :tree at the root of your project and see if React is not being overridden somewhere

anmonteiro21:03:13

also make sure to clean builds etc

henriqueqc21:03:00

@whythat @anmonteiro : I had the same problem once, an old version of React was being pulled by another dependency, lein deps :tree, showed the problem. Moving the om to the top of the :dependencies vector fixed-it.

anmonteiro21:03:52

it's definitely better to use :exclusions than to rely on the dependencies order

whythat21:03:23

@anmonteiro: well, it turned out that I was using old version of sablono which used react 13 while Om required 14, so that seems to be the problem. Thanks a lot.

henriqueqc21:03:52

@anmonteiro: Thanks for the tip

folcon22:03:45

for working with om next on devcards is there an explicit render step that needs to be taken?

folcon22:03:22

I鈥檝e managed to get it to work, but the cards weren鈥檛 updating, then I just discovered that you can select an individual card to load it. If I make a transaction that I would expect to update the devcard, it doesn鈥檛 update. After selecting a devcard to load it and pressing back, it suddenly works鈥 this is a little puzzling.

matthavener23:03:32

Folsom: might double check the checklist for writing figwheel compat code.. There are some def/defonce gotchas