Rails 4 - Display data inside a bootstrap modal via ajax - javascript

I have a pretty simple Ruby On Rails app with bootstrap 3 for the front end: I have Deals, and each Deal has_many Opportunities.
On each Deal page (url of deal 1 is like myapp.com/id=1), I want to have a textual link that says "view deal's opportunities" and that must trigger when clicked the appearance of content inside a Bootstrap modal.
Very basic but for specific reasons, I wish to load the content of the modal via Ajax.(the content is not visible when users load the Deal page but only when they click on the link 'view deal's opportunities'
I found many resources online for Rails4/ajax/Forms and other stuff with Ajax but not a simple "display content/text" inside a modal via Ajax. Should be easy but I'm stuck.
controller/deals_controller.rb
def showcase
deals = Deal.friendly.find(params[:id])
respond_to do |format|
format.html # showcase.html.erb
format.json { render json: #deal }
end
end
def show_opportunities
#opportunities = Opportunity.where('deal_id = ? AND deal_type = ?',
#deal.id, "high tech").first
respond_to do |format|
format.js
end
end
app/views/deals/showcase.html.erb
this is the beginning
<%= render 'deals/deal_info_zone' %>
this is the end
views/deals/_deal_info_zone.html.erb
<div id="zoneA">
<div style="color:red;padding-top: 150px;">
<%= link_to "view infos of Opportunities", deal_opportunities_modal_path, remote: true %>
</div>
</div>
Here is the modal I'd like to trigger via ajax: views/deals/opportunity_modal
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<%= #opportunity.name %> <br/>
</div>
</div>
</div>
</div>
routes.rb
match '/deals/:id', # this is the Deal page
to: 'deals#showcase',
via: 'get',
as: :deal_page
match '/opportunity_modal',
to: 'deals#show_opportunities',
via: 'get',
as: :deal_opportunities_modal
I'm a rookie in RoR and have never used ajax, ujs maybe... I feel it's missing things like javascript code and xhr request...
The current situation is this one: when I go on a Deal page (for ex page /deal id=1) the textual link "view infos of Opportunities". and the browser points to http://localhost:3000/opportunity_modal but it does not trigger anything when I click on it. Nothing happens. Nothing gets displayed btw on firebug console.

When you click a remote: true link, rails is not looking for opportunity_modal.html.erb, it's looking for opportunity_modal.js.erb. What you need to to do is put your modal in a partial, then render it with JavaScript.
Put your modal code into a partial named views/deals/_opportunity_modal.html.erb.
Create a views/deals/opportunity_modal.js.erb file that will render and show the modal when the this action is triggered.
$('body').append('<%= j render partial: "views/deals/opportunity_modal" %>');
$('#myModal').modal('show');
Also, you have a variable #opportunity in the modal, but it's not defined in your controller, so make sure to define that as well.

Related

Rails helper method seems to be killing my JQuery script

My application allows a user to make a list with different categories. While making a list, if the user decides they would like another category, they may create one without leaving the page. The new category will appear in the list, and the user can begin adding items to it.
My issue seems to be that adding any Rails helpers (link_to, render) to my 'new.js.erb' file, it stops the script from doing it's thing. My new div and dropdown menu are not rendered. I get no errors on the console or the server logs. Just nothing. If I remove these methods, everything works fine.
function addCategory(){
var lastCategory = '<%= current_user.categories[-2].name %>';
console.log(lastCategory);
$('#' + lastCategory).after("<h3 class='category'><%= #category.name %></h3>\
<div class='dropdown-button' data-toggle='collapse' data-target='#<%= #category.name %>'>\
<span class='glyphicon glyphicon-chevron-down'></span>\
</div>\
<div id='<%= #category.name %>' class='collapse'>\
<h4>Create a new item here:</h4>\
<div id='append<%= #category.id %>'></div>\
<%= link_to 'Home', root_url %>\ //does not work!
</div>");
}
It's just the link_to and other methods that seem to be causing a problem. All other erb tags <%= %> seem to work and render appropriately.
My goal is to render a form and a link in this newly rendered dropdown section, but since the root of the problem seems to be Rails methods in general, I added a link_to home for clarity.
Damnit, I figured it out. Forget to add 'j' to my rails helpers to convert them to JavaScript
<%= j link_to "Home", root_url %>

How to refresh the browser with JS after clicking a link_to tag in a Rails app

I'm trying to refresh the browser after the user clicks a link to an action that updates the database.
I want to avoid using redirect_back to prevent being sent back to the top of the screen after reload so I'm adding a JS click listener to the link_to tag with a code like this:
# in my view
<h5 class='my-link'><%= link_to 'vote', vote_path' %></h5>
# at the bottom of my application layout
<script>
$('.my-link').click(function (event) {
window.location.reload(true);
});
</script>
The JS code listener works OK in that if I click on any section of the h5 element the page will reload. However, when I click in the link the application will go to the relevant controller#action but the page wont reload.
I'm assuming I'm missing a way to execute first the link action and then force the refresh. So at click the app records a vote and then JS force a reload. Can you see any way I can achieve this? Thanks.
UPDATE
I some what solved this issue by adding a timer to the JS event so it gives time for the link to reach the controller and do the action and do the reload after it.
<script>
$(document).ready(function() {
$('.puke-icon, .clean-link, .comment-send').click(function() {
setTimeout(function(){
window.location.reload(true); },
50);
});
});
</script>
This is probably too hacky so hopefully you can provide more elegant approaches thanks!
In your vote controller action, use location.reload() in respond_to do format.
respond_to do |format|
format.js {render inline: "location.reload();" }
end
View:
<h5 class='my-link'><%= link_to 'vote', vote_path' %></h5>
Controller:
class VotesController < ApplicationController
def vote
----------------------
// your code goes here
----------------------
respond_to do |format|
format.js {render inline: "location.reload();" }
end
end
end
This will reload the page after the database action is completed.
$('.product').click(function () {
location.reload();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<div class="container">
<div class="row" id="footerRow">
<div class="col-xs-12 product">
<h2>Product</h2>
<div>
</div>
</div>

rails render view onclick with javascript

I'm trying to create a view, where users can click on different buttons and render different content based on the buttons they click. I've tried getting this done with JS but can't really get it to work. I made a button in my view:
<div class="link">
<%= link_to "Greetings", "#" %>
</div>
<div id="show"></div>
then in job.js.erb:
$(function() {
$('.link').click(function() {
$('#show').append("<%=escape_javascript render(:partial => 'show' %>");
});
});
unfortunately render is not supported in assets, but I don't really know what the best way is to make this happen.
One way you can try is to let the button click go to a controller action, by AJAX, and then render the file with name <action_name>.js.erb. this file will then be able to call the render action.
I will expatiate more with the following:
Assuming the resource in question is Greetings and you have a dynamic_show action in the Greetings controller, for example, and you have a dynamic_show_greetings_path routing to this action.
From inside your view, you can have:
<div class="link">
<%= link_to "Greetings", dynamic_show_greetings_path, remote: true %>
</div>
<div id="show"></div>
and the Greetings#dynamic_show action will be like follow:
def dynamic_show
respond_to do |format|
format.js
end
end
then, in your view directory, you have a dynamic_show.js.erb file, which will contain the script to append the dynamic view as follow:
$('#show').html("<%=escape_javascript render(:partial => 'show') %>");
And that solves it for you!
Of course, to now make it dynamic, you have to then pass in params to the controller, and then render content based on the response gotten.
PS:
setting remote: true on the link ensures that the call will be an AJAX call.
controller actions by default renders the file with same name as the action name, therefore, dynamic_show responding to js will render dynamic_show.js.erb
Hope this throws a great light into it for you... ;)
It sounds like you need jQuery for this.
You can wrap the rendered partial in a parent div with a hide class. When the button is clicked toggle displaying the content.
http://api.jquery.com/show/
$('#your-button').click(function(e){
$('.hidden-div').toggleClass('hide');
});
There are two ways to do this.
Firstly, if you're wanting to load the JS on-page, you need to use what #anchalee suggested, and preload the content with some sort of "hide" class in the CSS:
#app/assets/javascripts/application.js
$(document).on("click", "a.hidden", function(e){
e.preventDefault();
el = $(this).attr("href");
$(el).toggle();
});
#app/views/controller/your_view.html.erb
<%= link_to "User", "#user", class: "hidden" %>
<div id="user" class="hidden">
Hello
</div>
This will take any divs with the id specified by the href attribute of the link, and then make it so that the div will hide or show depending on its current state.
--
Secondly, you have the off-page method (using ajax).
This is used to get data from the server, and will be where you'd load server-centric data such as what you're trying to do now.
Doing this is actually quite simple:
#app/controllers/your_controller.rb
class YourController < ApplicationController
layout: Proc.new{|c| !c.request.xhr? }
end
This will return any data you need without the layout:
#app/assets/javascripts/application.js
$(document).on("click", "#show", function(e){
e.preventDefault();
$.get($(this).attr("href"), function(data){
$("#show").html(data);
});
});
#app/views/your_controller/show.html.erb
<%= link_to "Show", [[url for page]], id: "show" %>

RoR: destroy.js.erb not being run along with destroy action

My issue is that I expect on calling the destroy action of my swipe controller (which does work) that it would then call the javascript in the file app/views/swipes/destroy.js.erb. The idea being that on calling this file it will refresh my my-deck div and provide an updated web page. Unfortunately, although my destroy action is working, it doesn't seem to be calling the js correctly and I have to refresh the webpage to see that the item has been deleted.
Here are the relevant files, let me know if more info could be useful.
app/controllers/swipes_controller.rb
class SwipesController < ApplicationController
def new
end
app/views/swipes/destroy.js.erb
$(".my-deck").alert("Foo");
app/views/my_deck/show.html.erb
<p> Welcome to my deck! </p>
<p> When this is working your right swiped events should appear beautifully below! </p>
<div class="my-deck">
</div>
app/views/my_deck/_my_deck.html.erb
<p class="text-center">
There are no items in your shopping cart. Please <%= link_to "go back", home_path %> and add some items to your cart.
</p>
<% end %>
"app/views/my_deck/_card_row.html.erb"
<div class="well">
<div class="row">
<div class="col-xs-8">
<h4><%= event_id %></h4>
</div>
<div class="col-xs-4">
<div class="row">
<div class="col-xs-4">
</div>
<div class="col-xs-8 text-right">
<div class="btn-group">
<%= link_to "Delete", myCard, { data: { confirm: "Are you sure you wish to delete the product '#{myCard.event_id}' from your cart?"}, method: :delete, remote: true, class: "btn btn-danger" } %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>
Heres the output of my rails server when I click delete:
Swipe Load (0.8ms) SELECT "swipes".* FROM "swipes" WHERE "swipes"."id" = $1 LIMIT 1 [["id", 48]]
(0.1ms) BEGIN
(1.6ms) COMMIT
Rendered my_deck/_my_deck.html.erb (74.5ms)
Rendered swipes/destroy.js.erb (79.0ms)
Completed 500 Internal Server Error in 91ms (ActiveRecord: 3.0ms)
ActionView::Template::Error (undefined method `size' for nil:NilClass)
app/views/my_deck/_my_deck.html.erb:1:in `_app_views_my_deck__my_deck_html_erb___162867021113944140_70146212264540'
app/views/swipes/destroy.js.erb:1:in `_app_views_swipes_destroy_js_erb__359810691289434442_70146212224340'
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb (0.6ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb (0.7ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb (8.9ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.6ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.2ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.3ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.5ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (14.6ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.3ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.4ms)
Rendered /home/tomos/.rvm/gems/ruby-2.2.3/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (30.9ms)
If someone could help me figure out why app/views/swipes/destroy.js.erb is not running that'd be great. I'm following this tutorial.
This happens because destroy.js.erb
$(".my-deck").alert("Foo");
$(".my-deck").html("<%= escape_javascript(render 'my_deck/my_deck') %>");
renders app/views/my_deck/_my_deck.html.erb, that, in order, executes this line:
<% if #myDeck.size == 0 %>
Since you don't define #myDeck anywhere (neither in your controller's destroy action, nor in destroy.js.erb) this variable initializes to nil, which doesn't have any .size method, that causes error you have.
To fix the error you need either to properly initialize #myDeck var or to change your template so it won't access to uninitialized vars anymore (for example, remove line $(".my-deck").html("<%= escape_javascript(render 'my_deck/my_deck') %>");).
Have a nice day!
I had a similar problem when testing some ajax events, because something was missing on my action:
Here is what I added inside my destroy action:
respond_to do |format|
format.js
end
Try change your destroy to:
def destroy
#swipe = Swipe.find(params[:id])
if #swipe.destroy
redirect_to myDeck_path
end
respond_to do |format|
format.js
end
end
I hope it works for you.

How to load partial into view when a link is clicked?

I have a list of user 'submissions' in my Rails app, and when a user submission is clicked, I would like the full submission to load into the view, without having to go to a new page.
Here's the code for the list of submissions:
<div id="submission-list-container">
<% current_user.submissions.each do |i| %>
<a href='#'>
<div id="post-container">
<%= i.title %>
</div>
</a>
<% end %>
</div>
The partial I have created, <%= render "show", :submission => i %>,, works fine, but I would like the full submission to be loaded into the view (index.html.erb), when that link above is clicked. Is there a good method for doing this? Should I just do something else like an AJAX call in JavaScript? I like these partials because it feels more clean and organized to seperate code.
My partial is pretty simple at the moment:
<%= submission.title %>
<%= dat_markdown(submission.content) %>
You can do this using a TitlePane in the Dojo Toolkit, and probably there's a similar widget with jQueryUI.
I can only speak to the Dojo Toolkit's version
You would do something like:
<div data-dojo-type="dijit/TitlePane" data-dojo-props="href: '/blah', title: '<%= submission.title %>', open: false">
You can include this in your application layout for lite usage of dojo, loaded from a CDN:
<script data-dojo-config="async: true, parseOnLoad: true"></script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js"></script>
The TitlePane is wired up so that when it is expanded, it will autoload the content that is provided to the href parameter.
While this isn't exactly a rails solution directly, it can be used as an alternative.
For a Rails Solution, you can simply use an AJAX call to a controller that renders the partial. You may even be able to hook it up using the
def blah
#submission = Submission.find(...)
respond_to do |format|
format.html # default render
format.js # js behavior
end
end
then a blah.html.erb
<%= render partial: 'submission/submission', object: #submission %>
with the partial
<div id='submission-<%= submission.id %>'>
<div id='submission-<%= submission.id %>-title'><%= link_to(submission.title, 'blah/blah', remote: true) %></div>
<div id='submission-<%= submission.id %>-content'></div>
</div>
and a blah.js.erb
$.get('/submission/content', function(data) { $('#submission-<%= #submission.id %>-content').html(data) } );
and an entry into the submissions_controller with route
def content
#submission = Submission.find(...)
render text: #submission.content
end
This probably isn't an exact solution, but hopefully it'll put you on the right path.

Categories

Resources