Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fire 'turbo:frame-render' event after turbo frame renders the view #327

Merged
merged 7 commits into from
Aug 25, 2021

Conversation

kapantzak
Copy link
Contributor

@kapantzak kapantzak commented Jul 28, 2021

Hello all!

This PR introduces the turbo:frame-render event which
gets fired right after a turbo-frame element renders its view.

You can access the current turbo-frame id with event.detail.frameId with
event.target and the fetch response object with event.detail.fetchResponse.

@t27duck
Copy link
Contributor

t27duck commented Jul 29, 2021

Any reason why event.detail.frame couldn't be this.element which should be the actual turbo frame element instead of only its id?

@kapantzak
Copy link
Contributor Author

kapantzak commented Jul 29, 2021

Any reason why event.detail.frame couldn't be this.element which should be the actual turbo frame element instead of only its id?

Not really, just 2 concerns:

  • Is it better to carry the whole frame object inside the event's detail instead of just its id?
  • this.assert.equal(frame.id, 'part') fails (id is undefined)

If you think that we should send the object itself, please let me know and I'll change it!

@t27duck
Copy link
Contributor

t27duck commented Jul 29, 2021

* `this.assert.equal(frame.id, 'part')` fails (`id` is undefined)

I'm curious then how this is working in the code:

  const frame = this.element.id;
  dispatch("turbo:after-frame-render", { cancelable: true, detail: { fetchResponse, frame } })

If frame = this.element.id is getting the correct id, then why would frame = this.element being sent as part of the event detail result in frame.id being undefined?

If the id were to be the only thing passed, then perhaps naming it frameId instead of frame would make it more descriptive. To me, "frame" implies some form of object rather than its id.

@kapantzak
Copy link
Contributor Author

I'm curious then how this is working in the code:

I guess that the testing suite represents the elements in a different way, causing the frame element to have an undefined id.

If the id were to be the only thing passed, then perhaps naming it frameId instead of frame would make it more descriptive. To me, "frame" implies some form of object rather than its id.

Agree with the naming, if we pass only the id, frameId would be a better name 👍

@dhh dhh changed the title Fire 'turbo:after-fetch-render' event after turbo frame renders the view Fire 'turbo:after-frame-render' event after turbo frame renders the view Aug 23, 2021
@dhh
Copy link
Member

dhh commented Aug 23, 2021

I think the right event name should probably be turbo:frame-render to match turbo:render, no? Since the style is that these are automatically "after".

@dhh dhh changed the title Fire 'turbo:after-frame-render' event after turbo frame renders the view Fire 'turbo:frame-render' event after turbo frame renders the view Aug 23, 2021
@dhh
Copy link
Member

dhh commented Aug 23, 2021

Also, we should probably stick with the style where we declare this in Session following the form of notifyApplicationAfterFrameRender.

@dhh dhh added this to the 7.0.0 milestone Aug 23, 2021
@dhh
Copy link
Member

dhh commented Aug 24, 2021

We should pull in turbo:frame-load as well: #59

@dhh
Copy link
Member

dhh commented Aug 24, 2021

#59 is using this.element to put in the event, rather than the ID. I think that's a better form to follow here as well.

@kapantzak
Copy link
Contributor Author

Great! So, I'll try to implement notifyApplicationAfterFrameRender inside session and pass the element itself rather than the id, asap.

I will also pull in turbo:frame-load as well.

@kapantzak
Copy link
Contributor Author

I've pushed this commit which introduces the notifyApplicationAfterFrameRender inside session.

There, I've passed the frame element as the target of the event and removed it from the detail object, so, now we can get the frame element from the event.target property. I think it makes more sense this way, WDYT?

@dhh
Copy link
Member

dhh commented Aug 25, 2021

Looks good 👍

seanpdoyle and others added 2 commits August 25, 2021 19:10
Closes hotwired#54
Closes hotwired/turbo-rails#56

Dispatch `turbo:frame-load` lifecycle event when `<turbo-frame>` element
is navigated and finishes loading. The events bubble up, with the
`<turbo-frame>` element as the target.

Originally, this pull request involved numerous events, but in the
spirit of experimentation, we'll start with the one and see if others
are necessary.
@kapantzak
Copy link
Contributor Author

I also cherry-picked #59's commit and resolved some conflicts

@zeto
Copy link

zeto commented Apr 30, 2022

@kapantzak (thanks for the contribution!) context:

const html = await fetchResponse.responseHTML
if (html) {
  const { body } = parseHTMLDocument(html)
  const snapshot = new Snapshot(await this.extractForeignFrameElement(body))
  const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false)
  if (this.view.renderPromise) await this.view.renderPromise
  await this.view.render(renderer)
  session.frameRendered(fetchResponse, this.element)
  session.frameLoaded(this.element)
  this.fetchResponseLoaded(fetchResponse)
}

Assuming 🤔 the main intention to provide fetchResponse in the Event detail is to have access to the HTML Document, the most likely (?) use case would be something like:

document.addEventListener("turbo:frame-render", () => {
  event.detail.fetchResponse.responseHTML.then((html) => {
    const body = (new DOMParser()).parseFromString(html, "text/html")
  })
})

In order to avoid reparsing what was just parsed, the detail of the Event could have the already parsed body instead of the fetchResponse (or in addition to), seeing as at the time the Promise has already been fulfilled. Similar to the turbo:before-render event. Would this make sense ?

@kapantzak
Copy link
Contributor Author

Hello @zeto , I think it makes sense! But maybe we should just add it as an extra prop instead of replacing the old one in order to avoid breaking existing imementations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants