-
Notifications
You must be signed in to change notification settings - Fork 133
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
[#5610] Add turbo frames chapter #154
base: master
Are you sure you want to change the base?
Conversation
I didn't get the time to properly dive into this topic on Eager loading frames. Should I also add that once I return from the exams? |
Adding @lovro-bikic as well to the list of reviewers because he's familiar with the topic. |
|
||
With Turbo Frames, you can treat a subset of the page as its own component, where links and form submissions replace only that part. | ||
|
||
The way it works is: whenever the link inside a frame is clicked or form inside a frame is submitted, the frame content will automatically be updated after receiving a response. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way it works is: whenever the link inside a frame is clicked or form inside a frame is submitted, the frame content will automatically be updated after receiving a response. | |
## How it works | |
Whenever the link inside a frame is clicked or form inside a frame is submitted, the frame content will automatically be updated after receiving a response. |
h2 = 'Authors' | ||
|
||
- @authors.each do |author| | ||
= turbo_frame_tag "edit_author_#{author.id}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= turbo_frame_tag "edit_author_#{author.id}" | |
= turbo_frame_tag [:edit, dom_id(author)] |
|
||
The only required change was adding this line for each author: | ||
```ruby | ||
= turbo_frame_tag "edit_author_#{author.id}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= turbo_frame_tag "edit_author_#{author.id}" | |
= turbo_frame_tag [:edit, dom_id(author)] |
|
||
The view for the #edit action may look like this: | ||
```ruby | ||
= turbo_frame_tag "edit_author_#{@author.id}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we want to use render 'form'
? In that case, it wouldn't work because new
and edit
would have a different frame id.
Please try with the following and add it as a section in this chapter if it works (eg: Working with partials for forms):
= turbo_frame_tag [action_name, dom_id(@author)]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not work because the dom_id(@author)
for the #new action is new_author
so
= turbo_frame_tag [action_name, dom_id(@author)]
would generate the turbo frame with the new_new_author
id.
Also if there are some validation errors while editing, the action_name would be update
instead of edit
.
So we click on the link to add a new author, it acts as if it was clicked inside of a `'new_author'` frame because of the `data-turbo-frame` attribute. The response provided by the #new action will have its turbo-frame segment extracted and the content will replace the frame from on the index page. | ||
|
||
### target | ||
By default, navigation within a frame will target just that frame. But it can also drive another named frame by setting the `target` to the ID of that frame. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please elaborate a bit more for this section cause I find it hard to understand/visualize what's happening.
I think we should cover them if they provide us with concrete value 🙂 |
@gogi1805 please include the repo link to you dummy application somewhere as the last section. I see you included it in the useful links section, but I'd like to make a mention to the reader that they can clone the repo and how to set it up. Speaking of setting it up, after I ran:
I was getting an error telling me the application.css isn't found. I had to run The rest works fine and looks ok to me as a chapter👌 Let's wait for a couple more approvals before we merge this in 🙂 |
@lovro-bikic @uncoverd @vr4b4c please review this new Handbook chapter. |
I'm going to skip this one, I'm not familiar with this technology |
</turbo-frame> | ||
``` | ||
|
||
However, the second part (*Or it can drive another named frame by setting the target to the ID of that frame.*) doesn't seem to work in development without using turbo streams ([discussion](https://discuss.hotwired.dev/t/target-attribute-on-turbo-frame-tags/1959)) and `data-turbo-frame` attribute can be used to achieve the required functionality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an example on Atlas using target:
that works, you just have to put the target on both turbo frames.
Your previous example could be rewritten as:
# index.html.slim
= turbo_frame_tag 'main'
h2 = 'Authors'
= link_to 'Add author', new_author_path, data: { 'turbo-frame': dom_id(Author.new) }
= turbo_frame_tag Author.new, target: 'main' # <--
- @authors.each do |author|
= turbo_frame_tag "edit_author_#{author.id}"
.row
.col
= author.first_name
.col
= author.last_name
.col
= link_to 'Edit', edit_author_path(author.id)
# new.html.slim
= turbo_frame_tag Author.new, target: 'main' # <--
= simple_form_for @author do |f|
.row
.col
= f.input :first_name
.col
= f.input :last_name
.col
= f.button :submit
The gem is automatically configured for applications made with Rails 7+ unless --skip-hotwire was passed to the generator. | ||
Any new project that uses the [default-rails-template](https://github.com/infinum/default_rails_template) should have Turbo set up and ready to go. | ||
|
||
It can also be installed manually: | ||
1. Add the turbo-rails gem to your Gemfile: `gem 'turbo-rails'` | ||
2. Run `./bin/bundle install` | ||
3. Run `./bin/rails turbo:install` | ||
4. Add `import '@hotwired/turbo-rails'` to the Javascript entrypoint file, which is usually located in `app/javascript/application.js` or `app/webpack/packs/application.js` for apps using webpacker if it hasn't been automatically added in the previous step. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See turbo-rails
documentation for detailed installation instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe my intention wasn't clear, I would remove c/p of installation instructions and leave the reference to the official docs.
end | ||
``` | ||
|
||
NOTE: If you are using slim, make sure to name the views like `'index.html.slim'` instead of just `'index.slim'` because otherwise the form submissions won't work correctly! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: If you are using slim, make sure to name the views like `'index.html.slim'` instead of just `'index.slim'` because otherwise the form submissions won't work correctly! | |
NOTE: If you are using slim, make sure to name the views like `'index.html.slim'` instead of just `'index.slim'` because otherwise the [form submissions won't work correctly](https://github.com/hotwired/turbo-rails/issues/168)! |
This time we don't want to replace anything that's visible on the index page. | ||
We actually want to "append" the form for creating a new author to the page. | ||
|
||
If we used the same approach as for the inline editing, we would replace the link for creating a new user with the form. Maybe we don't want to do this because we don't want the form to appear at the same position where the button is, but somewhere else on the page. Luckily it is also done very easily with turbo frames. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we used the same approach as for the inline editing, we would replace the link for creating a new user with the form. Maybe we don't want to do this because we don't want the form to appear at the same position where the button is, but somewhere else on the page. Luckily it is also done very easily with turbo frames. | |
If we used the same approach as for the inline editing, we would replace the link for creating a new user with the form. Maybe we don't want to do this because we don't want the form to appear at the same position where the button is, but somewhere else on the page. Luckily it is also done very easily with frame targeting. |
|
||
The first change to our index page is the link to the new_author_path. This link is different to the one for the edit_author_path, because `data: { 'turbo-frame': dom_id(Author.new) }` was added to it. | ||
|
||
The `data-turbo-frame` attribute can be added on non-frame elements to control from which frame was the link clicked or the form submitted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The `data-turbo-frame` attribute can be added on non-frame elements to control from which frame was the link clicked or the form submitted. | |
The `data-turbo-frame` attribute can be added on non-frame elements to control which part of the page should be updated by user interaction with the element. |
end | ||
``` | ||
|
||
So we click on the link to add a new author, it acts as if it was clicked inside of a frame with the `new_author` id because of the `data-turbo-frame` attribute. The response provided by the #new action will have its turbo-frame segment extracted and the form for creating a new author will replace the empty frame with the same id from the index page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we click on the link to add a new author, it acts as if it was clicked inside of a frame with the `new_author` id because of the `data-turbo-frame` attribute. The response provided by the #new action will have its turbo-frame segment extracted and the form for creating a new author will replace the empty frame with the same id from the index page. | |
When the user clicks on the link to add a new author, the button sets the turbo frame target to `new_author`. Upon receiving the response, provided by the #new action, the `new_author` turbo-frame segment is extracted and the empty frame placeholder is replaced with the form content. |
The gem is automatically configured for applications made with Rails 7+ unless --skip-hotwire was passed to the generator. | ||
Any new project that uses the [default-rails-template](https://github.com/infinum/default_rails_template) should have Turbo set up and ready to go. | ||
|
||
It can also be installed manually: | ||
1. Add the turbo-rails gem to your Gemfile: `gem 'turbo-rails'` | ||
2. Run `./bin/bundle install` | ||
3. Run `./bin/rails turbo:install` | ||
4. Add `import '@hotwired/turbo-rails'` to the Javascript entrypoint file, which is usually located in `app/javascript/application.js` or `app/webpack/packs/application.js` for apps using webpacker if it hasn't been automatically added in the previous step. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe my intention wasn't clear, I would remove c/p of installation instructions and leave the reference to the official docs.
Task: #5610
Aim
Add chapter for turbo frames.
Solution
Explained a general idea of turbo frames, installation and setup steps, demonstrated the functionalities through code examples.