Fork me on GitHub
#om
<
2016-03-03
>
jplaza01:03:54

set-query! should trigger a remote send when the params change, right?

futuro01:03:56

@anmonteiro: In your Routing in Om Next post, you have a mutate function alter the query for your root component; does this mean that you're attaching functions to the onClick properties of dom elements in your components (as opposed to using something like secretary or bidi)?

tawus01:03:34

@futuro: This is function you can yourself call in the onClick event callback. You have to configure bidi/secretary yourself. You should look at https://github.com/kibu-australia/pushy which supports both bidi and secretary.

futuro01:03:55

@tawus: yeah, I was curious if @anmonteiro had made that choice or not. I'm guessing they did, but I hadn't considered that approach until now.

futuro01:03:51

specifically, it seems like they've completely bypassed history in general in their post, but I'm not certain

tawus02:03:58

There is a lein template from @anmonteiro where the history has been taken care of. https://github.com/anmonteiro/aemette.

futuro02:03:32

@tawus: oh, neat; thank you!

george.w.singer08:03:33

I'm trying to make a keyboard shortcut for an Om Next component. Basically, I'd like a component instance's handler function to be called whenever a key press is registered. I found a library for doing this with pure react.js: https://github.com/Chrisui/react-hotkeys I suppose I could use this with JS interop; however, I'm curious if people with more experience with Om Next have any suggestions of how to go about doing this?

george.w.singer08:03:06

Really, all I need to do is to bind a key which -- when pressed -- changes the reconciler's app-state via a (om/transact ..)

george.w.singer08:03:42

Since component's are a function of the app-state, I should be good

george.w.singer08:03:14

Any suggestions on how to do this (i.e., bind a keypress to a call to (om/transact! )?

rauh08:03:30

@george.w.singer: Check out KeyboardShortcutHandler in Google Closure. Then just use the normal lifecycle react methods

george.w.singer08:03:31

@rauh: brilliant suggestion! I had no idea this was stock a Google Closure concern. I presume I would follow the instructions here (but use cljs JS interop): http://www.andrewnoske.com/wiki/JavaScript_-_Shortcut_Keys#Setting_up_KeyPress_Events_using_Closure Would all of the stuff shown in that code snippet be within the component class definition (made via the defui macro)? Then, when a keypress is registered, it would call a method defined within the component class definition?

george.w.singer08:03:15

Here is the code snippet that I'm talking about:

goog.require('goog.dom');
goog.require('goog.events.KeyCodes');
goog.require('goog.ui.KeyboardShortcutHandler');
 
 
function showTriggered(event) {
  alert('Shortcut triggered: ' + event.identifier);
}
 
var shortcutHandler = new goog.ui.KeyboardShortcutHandler(document);
 
var NONE = goog.ui.KeyboardShortcutHandler.Modifiers.NONE;
var CTRL = goog.ui.KeyboardShortcutHandler.Modifiers.CTRL;
var SHIFT = goog.ui.KeyboardShortcutHandler.Modifiers.SHIFT;
var ALT = goog.ui.KeyboardShortcutHandler.Modifiers.ALT;
var META = goog.ui.KeyboardShortcutHandler.Modifiers.META;
 
shortcutHandler.registerShortcut('A', 'a');
shortcutHandler.registerShortcut('T E S T', 't e s t');
shortcutHandler.registerShortcut('SHIFT_F12', 'shift+f12');
shortcutHandler.registerShortcut('CTRL_A', goog.events.KeyCodes.A, CTRL);
shortcutHandler.registerShortcut('ENTER', goog.events.KeyCodes.ENTER);
 
goog.events.listen(
    shortcutHandler,
    goog.ui.KeyboardShortcutHandler.EventType.SHORTCUT_TRIGGERED,
    showTriggered);

george.w.singer08:03:46

@rauh: Thanks for your help. Very nicely laid out. Going to study that example for my own use case.

george.w.singer09:03:58

@rauh: the only thing I don't understand about your code snippet is what the #(goto % (route-home)) trigger function is doing. Is goto a component class method that you're calling?

rauh09:03:04

@george.w.singer: That's just the action you want to perform when ESC is pressed. In my case I route to home.

george.w.singer09:03:42

Does it have to be through goto? Or is that just a dummy function that you're using in this case?

george.w.singer09:03:16

More specifically: could I replace #(goto % (route-home)) with #(myComponentMethod ..)?

george.w.singer09:03:47

@rauh: nevermind. Calling component methods works fine.

anmonteiro11:03:49

@futuro: integrating with broswer history is orthogonal to routing, so I didn't include it in that post

grounded_sage13:03:59

Are there any examples of entirely client side uses of Om?

danielstockton13:03:34

@grounded_sage: The quick start and other articles on the wiki.

danielstockton13:03:35

Things are relatively straightforward until you start dealing with remotes

grounded_sage13:03:25

Ok I'm just more of a full example kind of guy. Been building a static site with Stasis, Garden and Hiccup following Atomic Design principles but it's become very fragile and complex workflow (I haven't even touched any JS yet!). Was thinking about using either Om or Reagent for the next website I need to build. I was told to just use Plain React, I don't want to spend time learning Webpack etc. Then I was told I could just use the script tag and use it without NPM. Though I have mixed feelings about using anything other than Reagent of Om for the website.

danielstockton13:03:32

just take any example you can find and ignore the remote parts

danielstockton13:03:45

the whole point of om is that it's easy to separate this stuff

danielstockton13:03:21

but i'm not sure it really fits your use-case, if you're after a static site

danielstockton13:03:35

surely there are better options for that

cjmurphy13:03:09

@grounded_sage: The kanban demo is a full example that's client-side only.

cjmurphy13:03:42

I can give you a link of a fork using lein instead boot if you like.

grounded_sage13:03:48

That would be great if you could @cjmurphy my Clojure chops aren't quite ready for Boot simple_smile Though I still will check out that example as I would love to learn Boot.

jlongster13:03:38

@iwankaramazow: turns out there were tons of places in my app that had perf problems, most of them very little to do with Om Next. I tore my app down to simple use cases and it appears that I can use Om's default DB format fine. (I started experimenting with my own DB format but I kept noticing other places where I was doing something stupid)

jlongster13:03:39

@iwankaramazow: it simplifies things a lot as well if I deal with batches of 1000 items, and no more. So 1000 items will load, and if you scroll all the way down and hit the bottom it'll load 1000 more. Om can handle batches of this size perfectly fine

jlongster13:03:29

@iwankaramazow: And I'm using VirtualScroll to optimize the displaying of them. I tried using InfiniteScroll which loads things on demand as you scroll but it's way too easy to produce too much network chatter

george.w.singer13:03:47

I am trying to read transit data from a cljs backend targetting nodejs/expressjs. Consider the following POST function on the backend (in expressJS):

(. app (post "/read" (fn [req res]
  (.dir js/console (t/read (t/reader :json) (aget req "body"))))))
This function is trying to read the transit data sent from the client within the req.body object. Yet this returns the error: `"SyntaxError: Unexpected token ~" Yet if I *stringify* the result, and then try to print it to the console, I get what is clearly transit data:
(. app (post "/read" (fn [req res]
  (.dir js/console (t/read (t/reader :json) (JSON/stringify (aget req "body")))))))
The value printed to my console from that is ["^ ","~:remote",["~:images/list","~:dir/current"]] So how can I get cljs-transit to convert the transit data from req.body into a cljs persistent data ѕtructure?

george.w.singer14:03:06

I earlier declared (.use app (.json bodyParser #js {:type "application/transit+json"})) in my code. I'm wondering if the issue is there? If I take out the ":type "application/transit+json"" bit, then req.body isn't even populated with a value.

jlongster15:03:06

@george.w.singer: don't use the json bodyParser, express is trying to parse it as json

jlongster15:03:19

I have (.use app (.text body-parser)) and then I POST it with a Content-Type of text/plain

george.w.singer15:03:30

@jlongster: what does your client POST look like?

george.w.singer15:03:05

(POST "/read"
      {
       :response-format {:content-type "text/plain"}
       :params  (t/write (t/writer :json) clj-data-to-send)         
       :handler (fn [res] (.log js/console (cb (t/read (t/reader :json) res))))
       :error-handler error-handler})
I tried adjusting to .text on the backend as you suggested, and used that snippet above^ on the front-end. It's still not working

jlongster15:03:20

(defn post [url data]
  (let [ch (chan)]
    (xhr/send
     url
     (fn [e]
       (put! ch (.getResponseText (.-target e))))
     "POST"
     data
     #js {:Content-Type "text/plain"})
    ch))

george.w.singer15:03:50

When I attempt to read the response on the back-end via

(.dir js/console (t/read (t/reader :json) (aget req "body")))
I'm getting this printed to my console:
{ meta: null,
  cnt: 1,
  arr: 
   [ { ns: null,
       name: 'remote',
       fqn: 'remote',
       _hash: null,
       'cljs$lang$protocol_mask$partition0$': 2153775105,
       'cljs$lang$protocol_mask$partition1$': 4096 },
     { meta: null,
       cnt: 2,
       shift: 5,
       root: [Object],
       tail: [Object],
       __hash: null,
       'cljs$lang$protocol_mask$partition0$': 167668511,
       'cljs$lang$protocol_mask$partition1$': 8196 } ],
  __hash: null,
  'cljs$lang$protocol_mask$partition0$': 16647951,
  'cljs$lang$protocol_mask$partition1$': 8196 }

george.w.singer15:03:23

Am I correct to be reading req.body? Is that where the transit data is at?

anmonteiro15:03:54

@george.w.singer: that seems correct, it's a CLJS data structure

anmonteiro15:03:04

if you print with println you might get a more readable thing

george.w.singer15:03:13

@jongster: Thanks for pointing me in the right direction. I think you're the only other person I know who uses clojurescript/node on the backend instead of clojure lol

jannis15:03:22

Is there a way to express for this component, always use the :db/id prop as the ident?

jannis15:03:58

If there isn't, would you up be willing to consider a PR for this, @dnolen?

jannis15:03:44

I'm guessing this would probably be a parameter to om.next/factory similar to :keyfn.

jannis15:03:16

:identfn basically 😉

anmonteiro15:03:04

@jannis: Do you mean as a shorthand?

anmonteiro15:03:35

Instead of having to implement Ident?

anmonteiro15:03:11

Implementing Ident let's you do just that (ident [this {:keys [db/id]}] [:items/by-id id]), but you already knew that

jannis15:03:49

As a shortcut. Imagine all your data being entities from e.g. Datomic or DataScript and they all have a :db/id, you'd have to write the same (ident ...) in all components.

anmonteiro15:03:51

But what would be the first element in the ident?

anmonteiro15:03:16

Would have to be different for all

anmonteiro15:03:19

Anyways, I don't think David is up for customization stuff like that, so I wish you luck 😉

danielstockton16:03:56

Yeah, sounds like something you could easily do yourself outside om

danielstockton16:03:15

Similar to having to add #js for om/dom attributes, there are lots of things like this that could be made slightly more convenient. I tend to agree that they don't need to be integrated into om.

ashercoren16:03:19

I want to use in my app both react-with-addons and bootstrap-cljs. But when in my code I call a bootstrap function, I get in the browser an error: ReactBootstrap is not defined. It seems to me that the problem is that in order to use react-with-addons I had to exclude the regular react package in my project.clj: [org.omcljs/om "0.9.0" :exclusions [cljsjs/react]]. Am I correct? Is there a way around it?

jannis16:03:05

anmonteiro: Well, if you use something like DataScript, all entities are uniquely identitifed by their :db/id. So you can safely use [:db/id (:db/id props)] for all components and have no clashes.

jannis16:03:24

No need for [:person/by-id (:db/id props)] for instance.

jannis16:03:30

@danielstockton: Yeah, you can do it if you wrap defui in a new macro for instance.

jannis16:03:43

I'm aware that it is possible. 😉

jannis16:03:18

I'm also aware that a lot of commercial projects that are picking up Om Next want to use DataScript in the client and they'll all face the same situation.

danielstockton16:03:42

i count myself in the datascript group, there are other problems that are bigger atm

danielstockton16:03:51

like having no solution to set-query!

anmonteiro16:03:40

@jannis: makes sense, but I also tend to agree that customization falls out of Om's scope

danielstockton16:03:31

Also, you might want another attribute than db/id even when using datascript. You can't update db/id, so how can you deal with optimistic mutations for example?

danielstockton16:03:09

I think at the very least, these kind of conveniences should be added when other more important things are settled and it becomes much clearer how everyone will use it.

jannis16:03:40

Sure, I wouldn't know how to disagree with that simple_smile

jasonf20:03:47

Hi Guys - I’m looking to use set-query! to change the query parameters of a component, but from a different component. Is this possible?!

iwankaramazow20:03:47

I do it all the time from my repl when developing

iwankaramazow20:03:47

(om/set-query! (om/class->any reconciler Component) :stuff)

jasonf20:03:30

cool, thanks!

tony.kay21:03:00

has anyone tried advanced optimizations yet in Om Next?

tony.kay21:03:46

thanks, I'll glance at that

anmonteiro22:03:16

@tony.kay: I think I've tried it with a very simple thing at some point

anmonteiro22:03:19

what problem are you having?

tony.kay22:03:38

compile error in cljsbuild...doesn't even touch the files

tony.kay22:03:49

java.lang.IllegalArgumentException: No implementation of method: :-find-sources of protocol: #'cljs.closure/Compilable found for class: nil

anmonteiro22:03:09

oh.. haven't bumped into that

anmonteiro22:03:27

I'm a bit busy now, I'll try it on my side when I can and let you know

tony.kay22:03:33

sure, thanks

tony.kay22:03:44

I copied the settings from om-next-demo, and now I get a different lovely error: java.lang.UnsupportedOperationException: nth not supported on this type: Symbol

jlongster22:03:22

@tony.kay: I tried it real quickly once and it compiled somehow, but it didn't run (some minification error). I assumed it was my fault with some 3rd party lib

tony.kay22:03:45

yeah, I've seen that...this one is new to me

jlongster22:03:10

why would it not work with optimized mode? it's all CLJS so shouldn't it work by default?

henriqueqc22:03:16

When recursively calling parse, If I return a remote, how do I get om to call send on that remote? Since the result of the recursive parse call is only the :value there is no :remote in the top level parse call.

tony.kay22:03:37

Found it. Duh...accidentally had something quoted that came from code, but is now in project.clj

henriqueqc22:03:02

Ok. got it, there is a third argument to parse that specifies target. The return value is then the :target instead of :value.... sorry for the noise

tony.kay22:03:12

well, that worked for whitespace. advanced still bombs for me

tony.kay22:03:34

Now back to: java.lang.IllegalArgumentException: No implementation of method: :-find-sources of protocol: #'cljs.closure/Compilable found for class: nil

tony.kay22:03:16

Ah. I gave it a main

tony.kay22:03:25

deleting main from the build config fixes it

tony.kay22:03:19

It did work, BTW, but I copied stuff from David's configs. For anyone interested, here is what I have:

tony.kay22:03:16

and externs.js has:

/**
 * @constructor
 */
React.Component = function() {};

tony.kay22:03:52

works: as in compiles, and runs correctly

anmonteiro22:03:20

@tony.kay: have you tried without externs?

anmonteiro22:03:33

I think that's something from the past which is not needed

anmonteiro22:03:45

because Om ships with its externs atm

tony.kay22:03:57

ok...I'll give it a shot

anmonteiro22:03:40

@tony.kay: one more thing: use :elide-asserts true in your advanced build to strip out Om invariants

tony.kay22:03:50

ah, nice. thanks

tony.kay22:03:44

@anmonteiro: Yeah, that seems ok too

tony.kay23:03:02

I have a bug...not sure if it is related to the compile or was something else