Rails call specific js.rb manually - javascript

I have this bit of code refreshing the event when I update it.
event/update.js.erb
$('#calendar').fullCalendar('removeEvents', [<%= #event.id %>]);
$('#calendar').fullCalendar(
'renderEvent',
$.parseJSON("<%=j render(#event, format: :json).html_safe %>"),
true
);
Lot of my events are related and I would like to be able to call this manually on every event every time as one of them is updated.
I'm trying to do something like this but I've no idea how to make the javascript call and it doesn't feel right either.
def update
#event.update(event_params)
Event.all.each do |event|
# call event's javascript
end
end
Any suggestions on this ?

If you want to do it every time, just do it in the view.
# controller
def update
#event.update(event_params)
#events = Event.all
end
# update.js.erb
<% #events.each do |event| %>
$('#calendar').fullCalendar('removeEvents', [<%= event.id %>]);
$('#calendar').fullCalendar(
'renderEvent',
$.parseJSON("<%=j render(event, format: :json).html_safe %>"),
true
);
<% end %>

Related

Limiting iterations on smaller screens

I'm iterating over few user objects and printing their profile avatar url as an image:
<% #users.each do |user| %>
<%= image_tag(user.profile.avatar.url, class: 'circle') %>
<% end %>
Nice. If I have 100+, I need to limit the image based on the end-user screen size, ie iPad:
<% #users.take(8).each do |user| %>
<%= image_tag(user.profile.avatar.url, class: 'circle') %>
<% end %>
I need to know how you pros do it. I have a javascript that listens for css changes:
// run test on initial page load
checkSize();
// run test on resize of the window
$(window).resize(checkSize);
function checkSize(){
if ($("#demo").css("display") == "none" ){
// ajax to get A (users.take(8).each ...)
} else {
// ajax to get B (initial view)
}
});
In the place that I call the ajax, I wanted to use render but render cant be used:
$("#some-id").html("<%= escape_javascript(render partial: 'foo/a') %>"); // or foo/b
I have omitted displaying the router and controller. The ajax calls an .js.erb file.
This feels like this is a matter of UI/UX decision on how to display those avatar images: should they be shown at all on smaller screens or not. But if I had to, how to limit the iteration on smaller screens?

Rails 4, turbolinks, and coffeescript

Forgive me if I'm a bit confused, I'm venturing out into new terratory in my programming, and learning as I go. The basic concept I'm struggling with:
In my Rails 4 app I'm using Leaflet (a JS library for mapping) and calling some of my own code. Long story short, I was unable to get Leaflet and Turbolinks to play well together so for the pages in my site that need Leaflet I've disabled Turbolinks, additionally I'm loading page specific Coffeescript.
I've now decided that I want to add a back button. The usage would go like this - from a page that is using Leaflet, the user can click on a piece of the map and be taken to a page that uses Turbolinks (if it matters). From the Turbolinks page, I have a back button to take you back to the Leaflet map.
However, when I get back to the Leaflet page, my coffeescript either isn't being run, or is being run at the wrong time (I get several errors that weren't there the first time it ran). I'm guessing I would need to add another event at the beginning of the Coffeescript or choose a different event, but I'm just not sure what it should be.
I am in no way wedded to not using Turbolinks on the Leaflet page if you have a suggestion for how to make it work and it helps to get the back button to work. :)
_navbar.html.erb
<li><%= link_to("By grid", grid_path, data: {turbolinks: false}) %></li>
grid.html.erb
... code for layout goes here ...
<% content_for :header do %>
<%= javascript_include_tag "leaflet" %>
<% end %>
<% content_for :javascript do %>
<%= javascript_include_tag "leaflet-maps/#{filename}" %>
<% end %>
leaflet-maps/grid.coffee
$ ->
document.addEventListener 'page:restore', ->
app.init()
return
... rest of coffeescript goes here ...
... here is how the link is getting called
layer.on 'click', (e) ->
window.location.href='/show?grid='+feature.id
return
show.html.erb
<%= link_to "Back", :back %>
Update
grid.coffee - full coffeescript code
ready = ->
#--------------------------------------------------
# Build tooltip with plant name
#--------------------------------------------------
onEachFeature = (feature, layer) ->
if feature.properties and feature.properties.grid_name
layer.bindTooltip feature.properties.grid_name
layer.on 'click', (e) ->
window.location.href='/show?grid='+feature.id
return
return
#--------------------------------------------------
# Variables
#--------------------------------------------------
L.Icon.Default.imagePath = '/assets'
gridStyle = {
"color": "#ff7800",
}
neCorner = L.latLng([47.635103, -122.320525])
swCorner = L.latLng([47.634083, -122.321129])
#--------------------------------------------------
# Set view and load Google Maps
#--------------------------------------------------
map = L.map("map", zoomSnap: .25)
map.fitBounds([swCorner, neCorner])
map.invalidateSize(false)
map.options.maxZoom = 22
map.options.bounceAtZoomLimits = true
googleLayer = L.gridLayer.googleMutant(type: 'roadmap').addTo(map)
map.addLayer googleLayer
#--------------------------------------------------
# Get Ajax data
#--------------------------------------------------
$.ajax
dataType: 'text'
url: 'grid.json'
success: (data) ->
L.geoJSON(JSON.parse(data), style: gridStyle, onEachFeature: onEachFeature ).addTo map
error: ->
alert "Failed to load AJAX data"
document.addEventListener 'turbolinks:load', ready()
document.addEventListener 'DOMContentLoaded', ready()
So, there are two places where you might be going off-track. The first is here:
$ ->
document.addEventListener 'page:restore', ->
app.init()
What this is saying is... "when the web page emits the DOMContentLoaded event, then, when something else emits the page:restore event, then, run my JavaScript code."
Let's start with DOMContentLoaded. This is an event browsers emit by default, and which the jQuery framework uses to trigger event listeners. You can read more about jQuery's .ready() function here.
The page:restore event is NOT a standardly-emitted event, but was a custom event used in Turbolinks Classic (version <5.0, deprecated as of February 2016), which I believe you're using since you mentioned Rails 4.
Either way, stacking both listeners on top of one another is probably not what you want to do. What you could do it define a function to run on both ready and page:restore...
function ready() {
// All of the setup you want to do...
}
document.addEventListener("turbolinks:load", ready());
document.addEventListener("DOMContentLoaded", ready());
(Sorry, I realize you're writing CoffeeScript. That's not my jam. I hope my JavaScript is OK...)
That's one. I see another opportunity for improvement.
layer.on 'click', (e) ->
What you're saying is "when the document is loaded, listen for clicks on the layer object, and then do this thing."
I'm not exactly sure what layer is, and if it's Leaflet-specific I probably won't be able to help you. However, there's actually a more resilient way to write this.
$(document).on("click","layer", function() {
// do things with the layer
});
This might seem identical, but there's a subtle difference. It's saying "any time I click on the document, if I also happen to be clicking on a layer, do this thing."
This is more resilient because your line of JavaScript can always find the document when it's run. If your layer hasn't rendered by the time that line of code runs, it'll never catch those clicks.
Happy JavaScripting! :)

Scroll bar jumps back to the top when the hide link is clicked

Actually I have got a more number of records in my index page with respective "hide"link on each record. Then problem is when I click the respective link it hides the record but moves to the top of the page, how do I stop this?
_rak361.html.erb
<%= link_to "Hide", hide_rak361_path(rak361), method: :put, class: 'stopper', style: "color:#ccc;" %>
ample.js
$( document ).ready(function() {
$(".stopper").click(function(event) {
event.preventDefault();
});
});
rak361s_controller.rb
def hide
#rak361 = Rak361.find(params[:id])
#rak361.hide
flash[:notice] = 'Rak361 was successfully hidden.'
redirect_to rak361s_url
end
I have tried but it is not working for me.
Any suggestions are most welcome.
Thank you in advance.
Thats because its a full page reload, first thing you need to to do is to use path helpers instead of mentioning controller and action in link_to, and the second thing is you should use remote: true option to ajaxify the request. Here's an example
= link_to "Hide", example_hide_path(id), method: :put, remote: true, class: 'stopper', style: "color:#ccc;"
Either you can use remote: true, or you can send an ajax request using jQuery's $.ajax().
Hope that helps!

Link not working after render partial js

So what I want is to re-render a table after updating an event.
I do it like this:
## My Controller:
respond_to do |format|
if schedule_child.save
sql = "schedules.doctor_id = ? AND schedules.location_id = ? AND schedule_children.start_time >= ? AND schedule_children.start_time <= ?"
#schedules = ScheduleChild.joins(:schedule).where(sql, current_doctor.id, session[:location_id], Time.now, Time.now + 7.days).order(start_time: :asc).page(params[:page]).per(7)
format.js {render :layout => false}
end
end
My js.erb:
$('#schedules').html( "<%= escape_javascript( render "schedules" ) %>" );
My view:
%a.status_link.btn.btn-success.btn-sm{"data-href" => set_schedule_status_path(location_id: session[:location_id] ,id: schedule.id), :style => "#{schedule.is_away ? 'display: none' : '' }", :id => "#{schedule.id}", :remote => "true"}
%i.fa.fa-check-square-o
%span Available
The table was successfully rendered but I cannot click the link in my view. What did I do wrong? Thanks for your help :)
The use of "data-href" as the link instead of "href" requires additional javascript to make the link available. Probably you have that javascript in place and are calling it on document.ready and apply your javascript logic on every link with the data property "data-href".
If this is the case you have four options (just guesses as I don't know what logic for data-href you are using):
Use href instead of data-href
Call the logic that enables the link in your js.erb (after you replaced the table)
Call the logic that enables the link on document.ready and ajaxStop
Define the logic on a parent node that exists always like $('body').on('click', 'a[data-href]', ...

Rails 4 Turbolinks make form submit multiple times

I use some code working nicely on Rails 3 but not on Rails 4, I guess it is caused by Turbolinks but I don't know much about it, can't dig more deep to solve my problem, here is the code:
view:
a/v/m/_new_comment.slim
.new-comment
- if current_user
= render "editor_toolbar"
= form_for(Comment.new, :remote => true, :url => mission_comments_path(#mission)) do |f|
= f.text_area :content, :class => "span10",
:rows => "4", :tabindex => "1"
#preview.hidden
= "Loading..."
= f.submit t("missions.submit_comment"),
"data-disable-with" => t("missions.submitting"),
:class => "btn btn-primary", :tabindex => "2"
- else
= render "need_login_to_comment"
controller:
def create
#mission = Mission.find(params[:mission_id])
#comment = #mission.comments.build(comment_params)
#comment.user = current_user
if #comment.save
#mission.events.create(user: current_user, action: "comment")
render layout: false
end
and js:
<% if #comment.errors.any? %>
$(".new-comment textarea").focus();
<% else %>
$(".comments").append("<%= j (render #comment, :index => #mission.comments.count-1) %>");
$(".new-comment #preview").addClass("hidden").html('');
$(".new-comment textarea").css("display", "block").val('');
$(".editor-toolbar .preview").removeClass("active");
$(".editor-toolbar .edit").addClass("active");
<% end %>
I have two question about this code, first: the controller code like this isn't work
the js code is transfer to client but not run, I have to add render layout: false at bottom of that action, no need this on Rails 3
second question: when I first visit this page, reload the page, comment function works, but if I click a link from other pages to jump to this page, I submit this form will cause ajax request call multiple times, multiple comments will be created
thanks in advs
Solved this by moving = javascript_include_tag "application", "data-turbolinks-track" => true from body to head, thanks all your help
You can leave it in the body, you just need to add to your script tag:
"data-turbolinks-eval" => false
In general, with turbolinks, it's best to make sure your code is "idempotent", so if it runs more than once, bindings won't get setup more than once.
The best way to do this is instead of $('blah').bind(), call unbind first:
$('blah').unbind('click').bind('click', function() {
One possible reason you could be running into issues is if you are including the js on every page. It's my understanding it will append the js to the head and if you have included it on multiple pages you could find yourself binding the ajax multiple times. That being said it's not apparent how you are including the js from what I saw. You could possibly solve this by only including the js file in your application.js

Categories

Resources