Good morning! I’m having problems with a component that is a child of a RAD form not updating. I’m wondering if anyone can see what I’m doing wrong?
The parent form is EpisodeForm. The child component is VideoPlayer.
When the VideoPlayer is playing a video, an event handler updates :ui/current-time, :ui/is-playing , etc. The changes show up in Fulcro Inspect.
However, the component doesn’t update when it’s a child of EpisodeForm. (It updates when I just render VideoPlayer normally, not as child of a Form.)
@tony.kay, based on our February conversation, I know the form isn’t fetching the data — ui/video-player in props is nil. I can’t figure out why…
Thank you!
(form/defsc-form EpisodeForm [this {:podcast-episode/keys [id title youtube-video-id podcast-id
video-id
listennotes-id listennotes-url pub_date_ms
vimeo-id
transcript-revai-raw
summaries
transcripts]
:ui/keys [relevant-time-min relevant-time-sec
relevant-text rewind duration
video-player]
:as props}]
{fo/id podcast-episode/id
fo/attributes [podcast-episode/youtube-video-id
podcast-episode/video-id
podcast-episode/vimeo-id
podcast-episode/title
podcast-episode/link]
fo/query-inclusion [:ui/relevant-time-min :ui/relevant-time-sec
:ui/relevant-text :ui/duration :ui/rewind
{:ui/video-player (comp/get-query vp/VideoPlayer)}
{:podcast-episode/summaries (comp/get-query stile/SummaryTile)}
{:podcast-episode/transcripts (comp/get-query transcript/Transcript)}
:podcast-episode/transcript-revai-raw]
fo/read-only-fields #{:photo/url :photo/product-url :photo/id}
fo/title "Edit Episode"
:componentDidMount (fn [this]
(jsu/set-document-title "Edit Episode"))
fo/route-prefix "episode-form1"}
(let [renv (form/rendering-env this props)
vimeo? (not (nil? vimeo-id))]
(def EPISODESAVE props)
(def SUMMARIES summaries)
(log/warn :EpisodeForm :vimeo? (if vimeo-id "Yes" "No"))
(dom/div
(form/render-layout this props)
(dom/div :.ui.bulleted.list
(if vimeo?
(dom/div
(log/warn :episode-form :vimeo/video-player video-player)
(log/warn :episode-form :vimeo/video-player (:vimeo/video-player props))
(log/warn :episode-form :props props)
(vp/ui-video-player
#_props
(merge props
#_{:video/id vimeo-id
:video/episode-id id}))))))))
VideoPlayer:
(defsc VideoPlayer [this {:podcast-episode/keys [id vimeo-id]
:ui/keys [current-time is-playing]
:as props}]
{:query [:podcast-episode/id
:podcast-episode/vimeo-id
:ui/current-time
:ui/is-playing]
:ident (fn [] [:component/id ::VideoPlayer])
:route-segment ["video-player"]
:initial-state {:podcast-episode/vimeo-id "1002127921"
:podcast-episode/id #uuid "7a37515d-bc68-4084-b34d-60355519926d"
:ui/is-playing false
:ui/current-time 1.0}
:will-enter (fn [app {:podcast-episode/keys [id vimeo-id]}]
(dr/route-deferred [:component/id ::VideoPlayer]
(fn []
(merge/merge-component! app VideoPlayer {:podcast-episode/vimeo-id vimeo-id})
(dr/target-ready! app [:component/id ::VideoPlayer]))))
:componentDidMount (fn [this]
(init-vimeo-player this))}
(let [player (comp/get-state this :player)]
(log/info "VideoPlayer render - Vimeo ID:" vimeo-id)
(log/info "VideoPlayer render" :current-time current-time)
(dom/div {:classes ["flex" "flex-col" "items-center" "w-full"]}
(dom/div {:classes ["w-3/4" "mx-auto"]}
(dom/p "Vimeo ID: " (str vimeo-id))
(dom/p
(dom/a {:href (str " " (str vimeo-id))
:target "_blank"}
"Link to Vimeo page (manage, download)"))
(dom/div :.w-full
(dom/iframe {:id "vimeoPlayer"
:src (str " " vimeo-id)
:width "100%"
:height "450"
:frameBorder "0"
:allow "autoplay; fullscreen; picture-in-picture"
:allowFullScreen true})
(dom/div {:classes ["flex" "mt-2" "justify-center"]}
#?(:cljs
(render-player-controls this player is-playing current-time props)))
(dom/p {:classes ["text-center"]} "Current playback time: " (str current-time))
;(dom/p {:classes ["text-center"]} "Current playback time: " (viewers/sec->min-and-sec current-time))
(dom/p {:classes ["mt-2" "text-center"]} "Playback state: " (if is-playing "Playing" "Paused")))))))You have to initialize them into state. Initial state doesn’t work on a form because it isn’t part of the data graph at application startup (there is no static instance of the form, so it and no children will be initialized)
You have them in the query…if you KNOW from other contexts that it is in the db always (from some other initialization), then yes of course you can use a link query instead of :ui/… But otherwise you need to mutate a link on that :ui/… field on form start
Thank you, Tony — are you saying that if I put it into state (via (swap! state […])?), that will get the machinery going?
I’d just start with an fo/triggers for started that adds them in then
See fo/triggers
Totally — Isn’t there a way to get those props into the form, so it can be passed back down to VideoPlayer? I feel like I’ve done something like this before…. Link Query? Thank you!
well, the props for video player won’t be “connected” in the db graph. You’ll need to manually initialize those addl props on the form, e.g. via a trigger or state machine modification. Forms have dynamic idents, so “initial state” of the video player isn’t going to be “joined in”. I’m no sure you it is ending up in state at all, other than you’re using mutations or something to write updates for it there…but if you look at your form’s state it won’t have a ref to that component.