Confusion about owner and inter component communication

138 views
Skip to first unread message

Paul Cowan

unread,
Nov 2, 2014, 9:15:32 AM11/2/14
to clojur...@googlegroups.com
I am confused about the role of the owner in om and how I can make the following component reusable.

I have this component that renders two textboxes:

https://gist.github.com/dagda1/b8a04c7516b62ea0eb46

On line 23 https://gist.github.com/dagda1/b8a04c7516b62ea0eb46#file-dash-cljs-L23 I render an input of type text that gets updated when an async call completes in IWillMount and works as I expect.

I tried to abstract this into a component https://gist.github.com/dagda1/0eed04662a90db2e4a66.

One thing I have noticed which confuses me when calling om/build, is that you never pass the owner in, for example I am calling it like this:

(om/build ui/text-box data {:opts {:value :title}})

But the component func has a signature like this:

(defn text-box [state owner {:keys [value]}]

So the framework must be supplying the owner, the docs say that the owner is the backing Om component so would that be the text-box in this case?

Also this line will never resolve https://gist.github.com/dagda1/0eed04662a90db2e4a66#file-component-cljs-L13 because I am guessing the owner is different.

So what is the best way of making this component reusable and updating when the property resolves from the calling component? Would I need to set up a core.async channel and listen for events and update the node's value? That seems a bit verbose for a simple case, is there a way of binding the two values together? Is there one-way binding in om that could accomplish this in a neater fashion? I am coming to om from workign with ember a lot and I'm probably still thinking in terms of bindingings.

Can anyone suggest a way to keep this as reusable as possible or how to approach this seemingly common problem in om?

Paul Cowan

unread,
Nov 2, 2014, 10:17:29 AM11/2/14
to clojur...@googlegroups.com
So I changed the text-box component to listen on a channel on IWIllMount

(will-mount [_]
(when-let [ch (om/get-shared owner [:channels :tab-changed])]
(go-loop []
(when-let [tab (<! ch)]
(do
(log/debug (str "we have received " (value tab)))
(om/set-state! owner value (value tab)))))))

And then I called put! from the parent component:

(will-mount [_]
(let [ch (get-active-tab)]
(go
(let [{:keys [tab]} (<! ch)]
(om/set-state! owner :title (:title tab))
(om/set-state! owner :url (:url tab))
(when-let [tab-changed (om/get-shared owner [:channels :tab-changed])]
(put! tab-changed tab))))))

I am also now rendering 2 of these text-boxes:

(om/build ui/text-box data {:opts {:value :title}})

(om/build ui/text-box data {:opts {:value :url}})

But the channel only receives a message on the first text-box component, do I have to do anything for the channel to broadcast on multiple listeners?

I am a bit new to clojurescript, om etc.

Paul Cowan

unread,
Nov 2, 2014, 2:18:52 PM11/2/14
to clojur...@googlegroups.com
So tab and mult fixed my problem of broadcasting to more than one listener https://gist.github.com/dagda1/4dcbda12f99aa9434ace#file-tap-cljs-L6.

I still think this is a very complicated solution to what I am trying to achieve.

Any input appreciated.

jack james

unread,
Nov 2, 2014, 7:36:23 PM11/2/14
to clojur...@googlegroups.com
It's very complicated, but I don't think it needs to be. You're using channels and ref-cursors in ways that introduce complexity without any benefit that i can see. For your purposes, I think it's a lot simpler without either:

https://www.refheap.com/92626

Or maybe i'm overlooking something?

Stephen Wakely

unread,
Nov 3, 2014, 5:41:25 AM11/3/14
to clojurescript
That would work getting data to the dom/input field. Presumably the next stage would be to make it so changes to the input field would then update the cursor.

Because the cursor passed into the text-box control is a primitive value, the cursor is a primitive value and not actually a cursor. So it isn't going to be as easy as just :

:onChange (fn [e] (om/transact! cursor field (fn [_] (.. e -target -value))))

There are a few options as I see it :

- Don't pass a primitive value as the cursor. If you could restructure your app-state so that :title and :url are maps rather than primitives :

(def app-state (atom {:clips [] :tab {:title {:value "loading"} :url {:value "loading"}}}))

then your update could be :

:onChange (fn [e] (om/transact! cursor :value (fn [_] (.. e -target -value))))

- You could pass the parent cursor (:tab) to the text-box control and pass a :field parameter to in the opts of the control.

(defn text-box [cursor _ {:keys [label field]}]
  (om/component
    (dom/div #js {:className "form-group"}
      (dom/label #js {:className "control-label"
                      :htmlFor label} label)
      (dom/div #js {:className "controls"}
        (dom/input #js {:className "input-vlarge"
                        :name label
                        :value (get cursor field)
                        :onChange (fn [e] (om/transact! cursor field (fn [_] (.. e -target -value))))})))))

- You could pass a call back in the opts which you call in the onChange.
- You could use core.async to send a message indicating the field is updated.


I'm not sure what the most idiomatic way would be. I'm only getting to grips with this stuff myself, so could be completely wrong or have missed out some other options.



--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to the Google Groups "ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at http://groups.google.com/group/clojurescript.

Paul Cowan

unread,
Nov 3, 2014, 10:34:31 AM11/3/14
to clojur...@googlegroups.com
Thanks @jack.james for bringing some sanity into the proceedings.

Part of what I was doing was to play around with core.async but I had passed the point of disappearing up my own backside.

Cheers

Paul Cowan

Cutting-Edge Solutions (Scotland)


On 3 November 2014 00:36, jack james <jack.jack...@gmail.com> wrote:
--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to a topic in the Google Groups "ClojureScript" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojurescript/O6sKnouXT_4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojurescrip...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages