I'm completely new to ruby on rails. Please help me out with the below use case.
By default flash messages are configured to timeout and fade in few seconds in application.html.erb
<div id="message" class="modal alert alert-error fade clear" data-alert="alert">
<%= flash[:notice] %>
</div>
Javascript code to set the timeout for the flash:
var showFlashMsg = function(){
<%if flash[:notice].nil?%>
return false;
<%else%>
return true;
<%end%>}
if(showFlashMsg()){
window.setTimeout(function () {
showMsg();
}, 100);
window.setTimeout(function () {
closeMsg();
}, 500);
}
showMsg() and closeMsg() holds #message.show() and #message.hide() functions.
But i'm trying to override that above mentioned behavior by making specific flash alert messages user dismissable (ie., adding the close button to the flash alert.) - in case the flash message is triggered when i submit the particular form.
So in this case, i need to override the default behavior set for the flash by adding the close button and removing the closeMsg() timeout for those flash. Except the flash messages which are displaying the form submission response, all the other flash messages triggered by same controller and the same action should follow above mentioned behavior of fading out within few seconds.
Please give me some suggestions on how to customize the flash messages only for the particular form submission response using javascript and rails?
Thanks in advance !!!
I'd rewrite the first bit of code as:
var showFlashMsg = <%= !flash[:notice].nil? %>
Then assuming you know what string you're looking out for in your notice:
<% special_string = "This is the special flash notice" %>
var showFlashMsg = <%= !flash[:notice].nil? %>
var setTimeout = <%= flash[:notice] && flash[:notice] != special_string %>
if(showFlashMsg){
window.setTimeout(function () {
showMsg();
}, 100)
}
if (setTimeout){
window.setTimeout(function () {
closeMsg();
}, 500);
}
This will set showFlashMsg to true if flash[:notice] is not nil, and setTimeout to true if it's not nil, and also doesn't equal the special string.
Related
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?
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! :)
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!
In my view I have a link_to for downloading an excel file:
<%= link_to 'Download Excel', url_for( :controller => "my_controller", :action => "file", :format => 'xlsx', :params => params ) %>
The controller uses axlsx to render the file like:
format.xlsx {
render xlsx: 'file', filename: 'filename', disposition: 'inline'
}
Now it can take a bit of time to generate and return that file, so I'd like to give the user an indication that the site's working.
I have a hidden div in the view code:
<div id="loader"><img src="/assets/loading.gif" ></div>
When someone clicks on the link, I can show the div with this jQuery:
$('#excel_export').click(function() {
$("#loader").show();
});
My question is: how can I .hide() that div when the file download starts? Maybe an ajax callback of some sort?
I don't know if this may help you. I found this code helpful to show spinner while an ajax request is performed.
$(document)
.ajaxStart(function() {
$("#loader").show();
})
.ajaxStop(function() {
$('#loader').hide();
});
You can get more samples from the following link.
You can use setTimeout() function by checking general time taken for download to start
Like this
$('#excel_export').click(function() {
$("#loader").show();
setTimeout($("#loader").hide();, 1000);
});
So it will be automatically close after 1000ms
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