Fragments.js
Fragments.js makes updating HTML page fragments easier. Instead of rendering the whole page and letting browser recompile the JavaScript and CSS, it replaces fragments of the current page with fragments found in the AJAX response.
Installation
Gem
Add fragments.js
gem to your application's Gemfile:
gem "fragments.js", github: "fs/fragments.js"
Require it in application.js
:
//= require fragments
Node
Yarn:
yarn add https://github.com/fs/fragments.js.git#commit_hash
WARNING: replace commit_hash
with actual commit hash!
Import inside your application:
// CommonJS
require('fragments.js');
// ES Modules
import 'fragments.js';
Usage
Add fragment to the page:
<%= form_for @comment, data: { remote: true, behavior: "fragments" } %>
<%= f.textarea :message %>
<%= f.submit "Post" %>
<% end %>
<%= render "discussion", comments: @comments %>
<%# _discussion.html.erb %>
<div class="discussion" data-fragment-id="discussion">
<%= render comments %>
</div>
After creating comment respond with fragments:
def create
# ...
@comment.save
render "discussion", comments: @comments, layout: false
end
And then element with the corresponding [data-fragment-id]
will be updated from AJAX response.
In our particular case discussion (comments list) will be updated.
Integration with JavaScript Libraries
Fragments.js replaces fragment contents with the data from AJAX response. That means that nodes on which you binded events on jQuery.ready no longer exist. So most jQuery plugins will stop working in updated fragments.
In order to restore such functionality after updating fragments
reinitialize required plugins/libraries on fragment:update
event:
$("input[placeholder]").placeholder()
$(".acts-as-chosen").chosen()
$(".acts-as-datatable").dataTable()
$(document).on("fragment:update", (e, $newContent) ->
$newContent.findAndFilter("input[placeholder]").placeholder()
$newContent.findAndFilter(".acts-as-chosen").chosen()
$newContent.findAndFilter(".acts-as-datatable").dataTable()
)
Bonus: highlight updated fragments
Fragments.js allows you to highlight new parts of the updated fragments.
All you need is to require one more file in application.js
(if you use it as Gem):
//= require fragments/highlight
And styles:
*= require fragments/highlight
Or if you use it as node module:
// CommonJS
require('fragments.js/lib/assets/javascripts/fragments/highlight');
// ES Modules
import 'fragments.js/lib/assets/javascripts/fragments/highlight';
And styles:
@import '~fragments.js/lib/assets/stylesheets/fragments/highlight.css';
Then set [data-highlight]
attribute on your fragment and
add data-updated-at
attribute to each child element (in our case to each comment block):
<div class="discussion" data-fragment-id="discussion" data-highlight>
<%= render comments %>
</div>
_comment.html.erb
:
<div class="comment" data-updated-at="<%= comment.updated_at.to_i %>">
<p><%= comment.body %></p>
</div>
You even can customize the behaviour by defining you own styles for .is-updated-fragment
class:
.is-updated-fragment {
animation-name: green;
animation-duration: .7s;
}
@keyframes green {
from { background: green; }
to { background: none; }
}
Do not forget to remove fragments/highlight
from your application.css
if have your own styles.
Credits
Thanks to Arthur Pushkin for his original work on this library.
Fragments.js is maintained by Vasily Polovnyov. It was written by Flatstack with the help of our contributors.