Fork me on GitHub
#om
<
2016-04-01
>
bmaddy03:04:11

Does anyone know why this would return an empty result?

om-tutorial.core=> (def app-state {:widget/people [[:people/by-id 1] [:people/by-id 2]],
                :people/by-id
                               {1 {:db/id 1, :person/name "Sam", :person/mate [:people/by-id 2]},
                                2 {:db/id 2, :person/name "Jenny", :person/mate [:people/by-id 1]}}})
#'om-tutorial.core/app-state
om-tutorial.core=> (om/db->tree '[[:people/by-id 2]] app-state app-state)
{}
The strange thing is that on a different project, which has the /exact/ same dependencies, It returns this:
toy-calc.core=> (om/db->tree '[[:people/by-id 2]] app-state app-state)
{[:people/by-id 2] {:db/id 2, :person/name "Jenny", :person/mate [:people/by-id 1]}}
I'm on om 1.0.0-alpha31 for both projects. Does anyone have any ideas?

bmaddy03:04:49

Oh, and I did run lein clean before getting both of those results.

cjmurphy04:04:22

Not answering your question, but I thought that db->tree was recursive, so the result would not have any idents in it. However you get back the person's mate as an ident. Interesting thing is though, if db->tree were to recurse with this data it would go on forever - because each person has the other as their mate.

cjmurphy04:04:45

For differences I would look at the component's ident methods - are they the same in both projects?

tomjack04:04:06

components are not involved

bmaddy04:04:31

Yeah, no components for this. I'm grabbing the example from the "Using db->tree" section from here: https://awkay.github.io/om-tutorial/#!/om_tutorial.E_State_Reads_and_Parsing

cjmurphy04:04:40

Yeah I read the example once. Good to know that db->tree doesn't need to know about ident methods. I get fixated on them b/c important for normalization 😝

tomjack04:04:35

well components can be involved in general, but not for this query

tomjack04:04:22

oh, yeah, not for db->tree I guess, though

tomjack04:04:31

anyway it doesn't make sense to me

tomjack04:04:42

you ran exactly that at the repl and copied it here?

bmaddy04:04:09

Yep, both snippets are copied and pasted from the repl that is started via rlwrap lein run -m clojure.main script/figwheel.clj. Both were done on the same computer so the ~/.lein/profiles.clj is the same and both have the exact same dependencies in the project.clj.

tomjack04:04:36

when you see om getting compiled, it's alpha31?

tomjack04:04:03

might try to reproduce without figwheel, I guess.. baffling

bmaddy04:04:36

Yep, I see lines like this in both projects:

Reading analysis cache for jar:file:/Users/bmaddy/.m2/repository/org/omcljs/om/1.0.0-alpha31/om-1.0.0-alpha31.jar!/om/core.cljs

tomjack04:04:08

on your lein clean runs it was something different, right?

bmaddy04:04:29

I see those lines right after I run lein clean. Is there another way I need to clean cljs stuff?

cjmurphy04:04:05

Still off topic a bit ☺️, but I see why it doesn't recurse forever now - because what is returned is determined by the query. At the end of the page you linked he gets the person's mate as well using [{[:people/by-id 1] [:person/name {:person/mate [:person/name]}]}].

cjmurphy04:04:59

You could get rid of the .js file.

bmaddy04:04:34

You mean resources/public/js/main.js?

cjmurphy04:04:35

In case your clean is not getting rid of it.

tomjack04:04:57

figwheel wants you to put :clean-targets ^{:protect false} ["resources/public/js" ...] in project.clj I think

bmaddy04:04:43

I get the same result (even when also doing a lein clean), but I'm still seeing the Reading analysis cache for prefix on each line. I suspect that means it's still cached somewhere.

cjmurphy04:04:06

Go incognito to remove the cache from the picture.

tomjack04:04:06

I would just rm -rf resources/public/js if you didn't put anything non-generated in there

tomjack04:04:32

or copy a :clean-targets from some figwheel example

bmaddy04:04:06

Oh! That worked!

bmaddy04:04:23

I'll look into the :clean-targets thing and get that set up correctly. I've been scratching my head on this one for quite a while now--thanks so much for your help you guys! 😄

tomjack04:04:57

I wonder what was in your cache

bmaddy04:04:30

Probably an old version of om. I've been trying a bunch of different things.

tomjack04:04:00

I was just experimenting wondering whether updates invalidate the cache properly

cjmurphy04:04:06

oh - so going incognito fixed the problem or rm -rf?

bmaddy04:04:25

rm -rf fixed it.

cjmurphy04:04:28

Seems more likely good.

jimmy08:04:37

@bmaddy: the best way to get it done correctly is to move your compiled js stuffs (for dev and test) to public/resources/cljs, then you can specify the whole clean-targets to that folder.

jimmy08:04:47

Hi guys, I have problem regarding transacting in omnext. the problem is: I have a hook into html5 history popstate event. Regarding popstate event, whenever there is an event, it will make a transaction to change :navigation-point which would swap the main component of the app. The problem is when I have a hook which is just printing stuffs out #(prn "stuff). The main component is swapped as expected. But in my case, I have a hook that send a message to modal component through a channel to make it close any modals it has. In this case, the hook does work ( all modals are closed as expected ), but the main component is not changed even though there is a transaction that change :navigation-point. Do you guys have any idea what's wrong?

iwankaramazow09:04:02

Without some code, it's pretty hard to guess what's wrong

jimmy09:04:41

@iwankaramazow: I will try to make a minimal gist. I have an idea for now, try to work on it then will get back soon.

iwankaramazow09:04:00

If you want to give your RootComponent some props when om/add-root!-ing. Should I go with local state? Or can I somehow use a factory with add-root!?

iwankaramazow09:04:30

(om/add-root!
 reconciler (rootview {:something "something-else"})
              (gdom/getElement "app")) 





jimmy09:04:30

i use local state it's more modular

iwankaramazow09:04:14

@nxqd: I'll give it a run

iwankaramazow09:04:46

@nxqd: I'm I right it's just set-state! in initLocalState ?

jimmy09:04:48

you should have default value in initLocalState

jimmy09:04:03

and you want to update-state! in componentWillMount

jimmy09:04:20

hmm, interesting discover.

jimmy09:04:05

regarding the problem I post above, I can see that if I try to do 2 or more actions that does mutate omnext at the same time, it only accepts one. But if I put a timeout between them, both are accepted. @anmonteiro maybe you have any idea regarding this.

iwankaramazow09:04:12

@nxqd: you could try to combine the mutations into one mutation if they should happen at once (as a workaround)

jimmy09:04:21

@iwankaramazow: yes it would be the solution. But the thing is my 2 mutations are so separated. One modifies the internal state of a component, other is the same. And both are being triggered through a signal through channel.

iwankaramazow10:04:07

@nxqd: maybe you can transduce the take on that channel, and transact the result?

jimmy10:04:01

good idea. But 2 uses 2 different channels.

jimmy10:04:08

haha 😄

jimmy10:04:49

but timeout 10 works for now. happy to move to another issue 😄

iwankaramazow10:04:01

Gotta love the daily issue grind

iwankaramazow10:04:59

I want to pass some kind of config in a defui/ui macro to configure some components when defining them. Seems I can't get it to work with a simple function like:

(defn component-creator [config] 
   (ui
  Object
  (initLocalState [this]
                     (do stuff with config))
  (render [this]
          (div nil "Hello, world!"))))
Is it possible to do such a thing?

cjmurphy10:04:36

Maybe in Reagent/reframe that would be possible. Not sure at all in Om Next. Can't you do something like send a function into the computed props of your component, or even different data. You can achieve all the variability you want with Om Next components I would have thought...

iwankaramazow10:04:52

@cjmurphy: I'm refactoring my router into something more modular, the idea is to pass in the history from the top. I'll try to explore the computed-props path, but I'm not sure if that's something I want.

cjmurphy10:04:05

Okay. Also set-query works for variability. unions and sub-query too.

jimmy10:04:45

@iwankaramazow: you should read the post from anmonteiro regarding routing in om next

iwankaramazow11:04:24

My router has been working since a few weeks, I'm trying to refactor everything

anmonteiro11:04:23

@iwankaramazow: you probably want to write a macro for the config thing

anmonteiro11:04:35

Not sure if a function will do it

iwankaramazow11:04:27

@anmonteiro: Ah damnit, I have been putting of learning macros for a long time now 😄

iwankaramazow11:04:48

Time to brew me some coffee & get it done

anmonteiro11:04:37

@nxqd: cant say nothing without a reproducible example

anmonteiro12:04:52

@iwankaramazow: it actually works with a function

anmonteiro12:04:07

(defn make-component [config]
  (ui
    Object
    (initLocalState [_]
      config)
    (render [this]
      (let [{:keys [a]} (om/get-state this)]
        (dom/div nil (str "config: " a))))))

(defui Parent
  Object
  (render [this]
    (dom/div nil
      ((om/factory (make-component {:a 2}))))))

anmonteiro12:04:10

I was curious so I tried it out

iwankaramazow13:04:27

@anmonteiro: indeed, I think I can make it work with ui

iwankaramazow13:04:51

Tried it before, but forgot to refer the macro in my namespace 😂

bmaddy13:04:51

Thanks for the tip @nxqd. That sounds like a great plan.

a.espolov16:04:55

@tony.kay: hi, untagled lein template is working?

tony.kay17:04:35

@a.espolov: Not yet. Use the todomvc project instead

tony.kay17:04:47

There is also an #C0PULSD25 channel

adamkowalski18:04:46

how would you go about implementing something like https://github.com/FormidableLabs/radium in om?

adamkowalski18:04:36

for those of you that are unfamiliar, it allows you to write all your css using js and inline styles, but they still support psuedo selectors, media queries, and anything else native css does

adamkowalski19:04:08

apparently they wrap your components render function and add on-mouse-over, on-mouse-leave to check whether or not you are being hovered over

adamkowalski19:04:45

but how could you make a component accept another component and then add these sorts of methods into its children?

adamkowalski19:04:15

i think you would somehow have to scan all the children of your component, and look for anything that uses a {:style …}, then parse through that map and look for a key ‘hover’ so that way you know to add the event handlers into that component

anmonteiro19:04:14

@adamkowalski: not quite the same, but om-css let's you colocate styles in your components, and outputs a file with such styles in the end: https://github.com/ladderlife/om-css

adamkowalski19:04:10

interesting, nice work

adamkowalski19:04:22

but do the styles leak with that implementation? as in if I have two components which both use the same class names what happens then?

adamkowalski19:04:31

ohh nvm, I just read that you prefix the namespace/component name

adamkowalski19:04:43

@anmonteiro: so I read through the examples and it seems like you have most of the functionality of radium, but can you use a function to generate the style? An obviously contrived example would be a component whose color changes as a function of some integer. Maybe a task has no background color if there is still plenty of time to complete it, but as the deadline approaches it gains a red hue.

anmonteiro19:04:58

@adamkowalski: because we actually generate a CSS file that you need to include in your markup, styles are static

anmonteiro19:04:32

so that case would be handled by having 2 different classes, and applying the red-hue class whenever time was almost over

adamkowalski19:04:41

right, I see what you are saying, and I get the benefits of static styles and having a css file. but for me I think there is a real tangible benefit to having dynamically generated styles. Like what if you wanted to transition from one thing to another. Or animation for example, rather than having to mess around with key frames, you could have a function which produces a different translation/rotation/scale/etc and easily make your animation stop whenever and go back to its original state if necessary

adamkowalski19:04:58

thats why I think the radium model is fascinating and I was always wondering if people are doing this in clojure or if there are any reasons that it is not popular

haywood21:04:56

I currently have a mutation that sets a property in state, but doesn't need to cause a re-render

haywood21:04:03

oddly it causes every element in the app to re-render

haywood21:04:24

(trying to implement drag-start / drag-stop)

haywood21:04:42

so when an element is hovered, the action checks to see if the dragging value is true

haywood21:04:11

I got this to work by directly swap!'ing (om/app-state reconciler)

haywood21:04:32

but I wanted to get it on the radar for history, even though it kind of doesn't matter

haywood21:04:16

I just can't figure out why it's causing everything to re-render, even though nothing relies on it

haywood21:04:22

there must be something about mutations that I don't understand, like if an element triggers a transaction, it is automatically re-rendered (and every item of it's kind)

haywood21:04:19

the event comes from a tile, which is in a grid that contains hundreds of instances of a tile

haywood21:04:44

every tile re-renders after this transaction

haywood21:04:42

I'm sorry this is not the case, the correct number of tiles re-render, but in my console I get [66060.501s] [om.next] [object Object] query took 49.81999999843538 msecs for each tile

haywood22:04:30

must be something with the full-query returning every tile component

uwo22:04:12

How would you compose the IQuery of something like the Autocomplete widget (in the Remote Synchronization Tutorial) with a Root component? I understand that the Root component needs a union of all its component’s subqueries, but I can’t get it to work for parameterized subqueries. Example fragment below:

anmonteiro22:04:20

@uwo: query composition is right

anmonteiro22:04:28

but you need to pass the props down

uwo22:04:18

oh darn. let me edit it. I am actually passing props in my working example

anmonteiro22:04:20

in the read method of :component, you can either use recursive parsing (to get the read method for :search/results called)

anmonteiro22:04:43

or have the logic for :search/results directly there and return it wrapped in {:search/results ...}

uwo22:04:45

as the autocomplete widget will ultimately get nested more deeply in the application, would it make more sense to do the latter?

anmonteiro22:04:57

it makes sense to keep the read method for :search/results because that's going to get called directly whenever set-query! is called

anmonteiro22:04:01

because of full-query

uwo23:04:38

I’ve edited the file above to include a read method for the :component key, and it’s now recursing into :search/results. Excellent! Unfortunately the remote portion of the :search/results read is no longer working. The remote was being fetched previously when Component was the target of add-root!. Thoughts?

uwo23:04:39

Something else strange: now the :search/results read method is firing twice

anmonteiro23:04:23

@uwo: nothing strange about either of those

uwo23:04:23

oh, good!

anmonteiro23:04:29

1. if you're using recursive parsing, :remote needs to be returned at top level

anmonteiro23:04:50

just like any recursive function

anmonteiro23:04:20

2. the read method is ran once for local targets (`target` = nil ) and once for every remote

uwo23:04:04

so this top level read is not sufficient?

(defmethod read :component
  [{:keys [query parser] :as env} k params]
  {:value (parser env query)})

anmonteiro23:04:20

you're never returning :remote in that read

anmonteiro23:04:34

all you ever return is :value

anmonteiro23:04:09

@uwo: my advice would not be to use recursive parsing, tbh

anmonteiro23:04:15

it's not needed there for sure

anmonteiro23:04:45

since it seems to be an autocompleter component, its read method will be called whenever there's a set-query! call

uwo23:04:53

yeah, I was wondering how I would know when to return remote, since that logic was already in the :search/restuls read

anmonteiro23:04:21

on the first render (in which the :component read method is called) you can just return whatever is in the state

anmonteiro23:04:44

or something like {:value {:search/results {}}}

anmonteiro23:04:58

it's important to return data matching the query, though

anmonteiro23:04:19

or Om won't know how to map data on subsequent renders (the call to set-query!) to the autocompleter component

uwo23:04:18

now that I’m doing

(defmethod read :component
  [{:keys [query parser] :as env} k params]
  {:value {:search/results []}})
I no longer see the :search/results read fire

anmonteiro23:04:24

right, that's expected

anmonteiro23:04:30

you don't see it in the first read

anmonteiro23:04:38

but as soon as you type something it should be called

uwo23:04:36

I was hoping that would be the case, but it never runs for me as I type

anmonteiro23:04:06

@uwo: 1. which version of Om are you using? 2. what's (om/path this) in your autocompleter component?

uwo23:04:26

i don’t know if this is right, but it’s apparently fixed by doing:

(defui Root
  static om/IQuery
  (query [this]
         [:comp]) ;removed (om/get-query Component)
...

uwo23:04:51

I’m using alpha32...

anmonteiro23:04:13

you should be able to get it working with the previous query

anmonteiro23:04:29

I've written that in a project with a similar query

uwo23:04:41

the path is [:comp]

anmonteiro23:04:01

ok the path is correct then

uwo23:04:39

yeah, with the the subquery removed from the Root it works just as it did when the Root had no IQuery implementation at all. Remote fetch occurs, but the data in the app state doesn’t immediately cause a rerender in the Component. Though this could be an unrelated bug (in my app)

anmonteiro23:04:08

@uwo: right but that'll cause you problems down the road

anmonteiro23:04:15

the query should compose to the root

uwo23:04:59

right. I’m going to create a repo with a minimal example so this is easier to discuss simple_smile